Skip to content

[msal-node][msal-common] Update generation of client info headers #1482

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 28, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions lib/msal-common/src/client/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,12 @@ export abstract class BaseClient {
*/
protected createDefaultLibraryHeaders(): Map<string, string> {
const headers = new Map<string, string>();
// library version
headers.set(`${AADServerParamKeys.X_CLIENT_SKU}`, Constants.LIBRARY_NAME);
headers.set(`${AADServerParamKeys.X_CLIENT_VER}`, "0.0.1");
// client info headers
headers.set(`${AADServerParamKeys.X_CLIENT_SKU}`, this.config.libraryInfo.sku);
headers.set(`${AADServerParamKeys.X_CLIENT_VER}`, this.config.libraryInfo.version);
headers.set(`${AADServerParamKeys.X_CLIENT_OS}`, this.config.libraryInfo.os);
headers.set(`${AADServerParamKeys.X_CLIENT_CPU}`, this.config.libraryInfo.cpu);

return headers;
}

Expand Down
54 changes: 39 additions & 15 deletions lib/msal-common/src/config/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

import { ICacheStorage } from "../cache/ICacheStorage";
import { INetworkModule } from "../network/INetworkModule";
import { ICrypto, PkceCodes } from "../crypto/ICrypto";
import { AuthError } from "../error/AuthError";
import { ILoggerCallback, LogLevel } from "../logger/Logger";
import { Constants } from "../utils/Constants";
import { version } from "../../package.json";

// Token renewal offset default in seconds
const DEFAULT_TOKEN_RENEWAL_OFFSET_SEC = 300;
Expand All @@ -26,7 +29,8 @@ export type Configuration = {
loggerOptions?: LoggerOptions,
storageInterface?: ICacheStorage,
networkInterface?: INetworkModule,
cryptoInterface?: ICrypto
cryptoInterface?: ICrypto,
libraryInfo?: LibraryInfo
};

/**
Expand All @@ -43,7 +47,7 @@ export type AuthOptions = {
/**
* Telemetry Config Options
* - applicationName - Name of the consuming apps application
* - applicationVersion - Verison of the consuming application
* - applicationVersion - Version of the consuming application
* - telemetryEmitter - Function where telemetry events are flushed to
*/
export type TelemetryOptions = {
Expand Down Expand Up @@ -72,18 +76,26 @@ export type LoggerOptions = {
logLevel?: LogLevel
};

/**
* Telemetry info about library
*/
export type LibraryInfo = {
sku: string,
version: string,
cpu: string,
os: string
};

const DEFAULT_AUTH_OPTIONS: AuthOptions = {
clientId: "",
authority: null
};

// Default module system options
const DEFAULT_SYSTEM_OPTIONS: SystemOptions = {
tokenRenewalOffsetSeconds: DEFAULT_TOKEN_RENEWAL_OFFSET_SEC,
telemetry: null
};

// Default logger implementation
const DEFAULT_LOGGER_IMPLEMENTATION: LoggerOptions = {
loggerCallback: () => {
const notImplErr = "Logger - loggerCallbackInterface() has not been implemented.";
Expand All @@ -93,7 +105,6 @@ const DEFAULT_LOGGER_IMPLEMENTATION: LoggerOptions = {
logLevel: LogLevel.Info
};

// Default storage implementation
const DEFAULT_STORAGE_IMPLEMENTATION: ICacheStorage = {
clear: () => {
const notImplErr = "Storage interface - clear() has not been implemented for the cacheStorage interface.";
Expand Down Expand Up @@ -121,7 +132,6 @@ const DEFAULT_STORAGE_IMPLEMENTATION: ICacheStorage = {
}
};

// Default network implementation
const DEFAULT_NETWORK_IMPLEMENTATION: INetworkModule = {
async sendGetRequestAsync<T>(): Promise<T> {
const notImplErr = "Network interface - sendGetRequestAsync() has not been implemented";
Expand All @@ -133,7 +143,6 @@ const DEFAULT_NETWORK_IMPLEMENTATION: INetworkModule = {
}
};

// Default crypto implementation
const DEFAULT_CRYPTO_IMPLEMENTATION: ICrypto = {
createNewGuid: (): string => {
const notImplErr = "Crypto interface - createNewGuid() has not been implemented";
Expand All @@ -153,23 +162,38 @@ const DEFAULT_CRYPTO_IMPLEMENTATION: ICrypto = {
}
};

const DEFAULT_LIBRARY_INFO: LibraryInfo = {
sku: Constants.SKU,
version: version,
cpu: process.platform || "",
os: process.arch || "",
};

/**
* Function that sets the default options when not explicitly configured from app developer
*
* @param TStorageOptions
* @param TSystemOptions
* @param TFrameworkOptions
* @param Configuration
*
* @returns MsalConfiguration object
* @returns Configuration
*/
export function buildConfiguration({ authOptions: authOptions, systemOptions: userSystemOptions, loggerOptions: userLoggerOption, storageInterface: storageImplementation, networkInterface: networkImplementation, cryptoInterface: cryptoImplementation }: Configuration): Configuration {
const overlayedConfig: Configuration = {
export function buildConfiguration(
{
authOptions: authOptions,
systemOptions: userSystemOptions,
loggerOptions: userLoggerOption,
storageInterface: storageImplementation,
networkInterface: networkImplementation,
cryptoInterface: cryptoImplementation,
libraryInfo: libraryInfo
} : Configuration): Configuration {

return {
authOptions: authOptions || DEFAULT_AUTH_OPTIONS,
systemOptions: userSystemOptions || DEFAULT_SYSTEM_OPTIONS,
loggerOptions: userLoggerOption || DEFAULT_LOGGER_IMPLEMENTATION,
storageInterface: storageImplementation || DEFAULT_STORAGE_IMPLEMENTATION,
networkInterface: networkImplementation || DEFAULT_NETWORK_IMPLEMENTATION,
cryptoInterface: cryptoImplementation || DEFAULT_CRYPTO_IMPLEMENTATION
cryptoInterface: cryptoImplementation || DEFAULT_CRYPTO_IMPLEMENTATION,
libraryInfo: libraryInfo|| DEFAULT_LIBRARY_INFO
};
return overlayedConfig;
}
7 changes: 5 additions & 2 deletions lib/msal-common/src/utils/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
*/

export const Constants = {
LIBRARY_NAME: "MSAL.JS",
LIBRARY_NAME: "MSAL.JS", // TODO JS should be broken up into common, browser, node. What dore core/angular use?
SKU: "MSAL.JS.common",
// Prefix for all library cache entries
CACHE_PREFIX: "msal",
// default authority
Expand Down Expand Up @@ -121,7 +122,9 @@ export enum AADServerParamKeys {
CODE_VERIFIER = "code_verifier",
CLIENT_REQUEST_ID = "client-request-id",
X_CLIENT_SKU = "x-client-SKU",
X_CLIENT_VER = "x-client-Ver",
X_CLIENT_VER = "x-client-VER",
X_CLIENT_OS = "x-client-OS",
X_CLIENT_CPU = "x-client-CPU",
POST_LOGOUT_URI = "post_logout_redirect_uri",
DEVICE_CODE = "device_code"
};
Expand Down
13 changes: 9 additions & 4 deletions lib/msal-common/test/client/BaseClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {Constants} from "../../src";
import {AADServerParamKeys, HeaderNames} from "../../src/utils/Constants";
import {ClientTestUtils} from "./ClientTestUtils";
import sinon from "sinon";
import {TEST_CONFIG} from "../utils/StringConstants";

class TestClient extends BaseClient {

Expand Down Expand Up @@ -96,17 +97,21 @@ describe("BaseClient.ts Class Unit Tests", () => {
const client = new TestClient(config);
const headers = client.createDefaultLibraryHeaders();

expect(headers.get(AADServerParamKeys.X_CLIENT_SKU)).to.eq(Constants.LIBRARY_NAME);
expect(headers.get(AADServerParamKeys.X_CLIENT_VER)).to.eq("0.0.1");
expect(headers.get(AADServerParamKeys.X_CLIENT_SKU)).to.eq(Constants.SKU);
expect(headers.get(AADServerParamKeys.X_CLIENT_VER)).to.eq(TEST_CONFIG.TEST_VERSION);
expect(headers.get(AADServerParamKeys.X_CLIENT_OS)).to.eq(TEST_CONFIG.TEST_OS);
expect(headers.get(AADServerParamKeys.X_CLIENT_CPU)).to.eq(TEST_CONFIG.TEST_CPU);
});

it("Creates default token request headers", () => {

const client = new TestClient(config);
const headers = client.createDefaultTokenRequestHeaders();

expect(headers.get(AADServerParamKeys.X_CLIENT_SKU)).to.eq(Constants.LIBRARY_NAME);
expect(headers.get(AADServerParamKeys.X_CLIENT_VER)).to.eq("0.0.1");
expect(headers.get(AADServerParamKeys.X_CLIENT_SKU)).to.eq(Constants.SKU);
expect(headers.get(AADServerParamKeys.X_CLIENT_VER)).to.eq(TEST_CONFIG.TEST_VERSION);
expect(headers.get(AADServerParamKeys.X_CLIENT_OS)).to.eq(TEST_CONFIG.TEST_OS);
expect(headers.get(AADServerParamKeys.X_CLIENT_CPU)).to.eq(TEST_CONFIG.TEST_CPU);
expect(headers.get(HeaderNames.CONTENT_TYPE)).to.eq(Constants.URL_FORM_CONTENT_TYPE);
});
});
Expand Down
8 changes: 7 additions & 1 deletion lib/msal-common/test/client/ClientTestUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Configuration, LogLevel, NetworkRequestOptions, PkceCodes} from "../../src";
import {Configuration, Constants, LogLevel, NetworkRequestOptions, PkceCodes} from "../../src";
import {RANDOM_TEST_GUID, TEST_CONFIG} from "../utils/StringConstants";

export class ClientTestUtils {
Expand Down Expand Up @@ -64,6 +64,12 @@ export class ClientTestUtils {
},
loggerOptions: {
loggerCallback: testLoggerCallback
},
libraryInfo: {
sku: Constants.SKU,
version: TEST_CONFIG.TEST_VERSION,
os: TEST_CONFIG.TEST_OS,
cpu: TEST_CONFIG.TEST_CPU,
}
};
}
Expand Down
20 changes: 20 additions & 0 deletions lib/msal-common/test/config/Configuration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { PkceCodes } from "../../src/crypto/ICrypto";
import { AuthError } from "../../src/error/AuthError";
import { NetworkRequestOptions } from "../../src/network/INetworkModule";
import { LogLevel } from "../../src/logger/Logger";
import { Constants } from "../../src";
import { version } from "../../package.json";
import {TEST_CONFIG} from "../utils/StringConstants";

const expect = chai.expect;
chai.use(chaiAsPromised);

Expand Down Expand Up @@ -57,6 +61,11 @@ describe("Configuration.ts Class Unit Tests", () => {
expect(() => emptyConfig.loggerOptions.loggerCallback(null, "", false)).to.throw("Unexpected error in authentication.: Logger - loggerCallbackInterface() has not been implemented.");
expect(() => emptyConfig.loggerOptions.loggerCallback(null, "", false)).to.throw(AuthError);
expect(emptyConfig.loggerOptions.piiLoggingEnabled).to.be.false;
// Client info checks
expect(emptyConfig.libraryInfo.sku).to.be.eq(Constants.SKU);
expect(emptyConfig.libraryInfo.version).to.be.eq(version);
expect(emptyConfig.libraryInfo.os).to.be.eq((process.arch || ""));
expect(emptyConfig.libraryInfo.cpu).to.be.eq((process.platform || ""));
});

const clearFunc = (): void => {
Expand Down Expand Up @@ -127,6 +136,12 @@ describe("Configuration.ts Class Unit Tests", () => {
}
},
piiLoggingEnabled: true
},
libraryInfo: {
sku: TEST_CONFIG.TEST_SKU,
version: TEST_CONFIG.TEST_VERSION,
os: TEST_CONFIG.TEST_OS,
cpu: TEST_CONFIG.TEST_CPU
}
});
// Crypto interface tests
Expand Down Expand Up @@ -161,5 +176,10 @@ describe("Configuration.ts Class Unit Tests", () => {
expect(newConfig.loggerOptions).to.be.not.null;
expect(newConfig.loggerOptions.loggerCallback).to.be.not.null;
expect(newConfig.loggerOptions.piiLoggingEnabled).to.be.true;
// Client info tests
expect(newConfig.libraryInfo.sku).to.be.eq(TEST_CONFIG.TEST_SKU);
expect(newConfig.libraryInfo.version).to.be.eq(TEST_CONFIG.TEST_VERSION);
expect(newConfig.libraryInfo.os).to.be.eq(TEST_CONFIG.TEST_OS);
expect(newConfig.libraryInfo.cpu).to.be.eq(TEST_CONFIG.TEST_CPU);
});
});
6 changes: 5 additions & 1 deletion lib/msal-common/test/utils/StringConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ export const TEST_CONFIG = {
LOGIN_HINT: "[email protected]",
DOMAIN_HINT: "test.com",
CORRELATION_ID: "7821e1d3-ad52-42t9-8666-399gea483401",
CLAIMS: "claims"
CLAIMS: "claims",
TEST_SKU: "test.sku",
TEST_VERSION: "1.0.0",
TEST_OS: "win32",
TEST_CPU: "x86",
};

export const RANDOM_TEST_GUID = "11553a9b-7116-48b1-9d48-f6d4a8ff8371";
Expand Down
22 changes: 12 additions & 10 deletions lib/msal-node/src/client/ClientApplication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import {
AuthorizationCodeRequest,
Configuration,
} from '@azure/msal-common';
import { ClientConfiguration, buildConfiguration } from '../config/ClientConfiguration';
import { ClientConfiguration, buildAppConfiguration } from '../config/ClientConfiguration';
import { CryptoProvider } from '../crypto/CryptoProvider';
import { Storage } from '../cache/Storage';
import { version } from '../../package.json';
import { ClientInfo } from "./../utils/Constants";

export abstract class ClientApplication {

// Input configuration by developer/user
protected config: ClientConfiguration;

/**
Expand All @@ -34,14 +35,12 @@ export abstract class ClientApplication {
* If your application supports Accounts in any organizational directory and personal Microsoft accounts, replace "Enter_the_Tenant_Info_Here" value with common.
* To restrict support to Personal Microsoft accounts only, replace "Enter_the_Tenant_Info_Here" value with consumers.
*
* In Azure B2C, authority is of the form https://{instance}/tfp/{tenant}/{policyName}/
* Full B2C functionality will be available in this library in future versions.
* In Azure B2C, authority is of the form https://{instance}/tfp/{tenant}/{policyName}/ls
*
* @param {@link (Configuration:type)} configuration object for the MSAL PublicClientApplication instance
*/
protected constructor(configuration: ClientConfiguration) {

this.config = buildConfiguration(configuration);
this.config = buildAppConfiguration(configuration);
}

/**
Expand Down Expand Up @@ -86,10 +85,13 @@ export abstract class ClientApplication {
},
cryptoInterface: new CryptoProvider(),
networkInterface: this.config.system!.networkClient,
storageInterface: new Storage(
this.config.auth!.clientId,
this.config.cache!
),
storageInterface: new Storage(this.config.auth!.clientId, this.config.cache!),
libraryInfo: {
sku: ClientInfo.MSAL_SKU_VALUE,
version: version,
cpu: process.platform || "",
os: process.arch || ""
},
};
}
}
2 changes: 1 addition & 1 deletion lib/msal-node/src/config/ClientConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ const DEFAULT_SYSTEM_OPTIONS: NodeSystemOptions = {
*
* @returns ClientConfiguration
*/
export function buildConfiguration({
export function buildAppConfiguration({
auth,
cache,
system,
Expand Down
2 changes: 1 addition & 1 deletion lib/msal-node/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export { PublicClientApplication } from './client/PublicClientApplication';
export { ConfidentialClientApplication } from './client/ConfidentialClientApplication';
export { ClientConfiguration, buildConfiguration } from './config/ClientConfiguration';
export { ClientConfiguration, buildAppConfiguration } from './config/ClientConfiguration';
export { Storage } from './cache/Storage';

// crypto
Expand Down
7 changes: 3 additions & 4 deletions lib/msal-node/src/utils/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,10 @@ export const CACHE = {
/**
* Constants for headers
*/
export const Header = {
export const ClientInfo = {
MSAL_SKU_KEY: "x-client-SKU",
MSAL_SKU_VALUE: "MSAL.node",
MSAL_SKU_VALUE: "msal.node",
MSAL_VERSION: "x-client-VER",
CPU: "x-client-CPU",
OS: "x-client-OS"
// TODO will also add appName and appVersion here
}
};
24 changes: 0 additions & 24 deletions lib/msal-node/src/utils/HeaderUtils.ts

This file was deleted.

Loading