Skip to content

Commit

Permalink
Merge branch 'dev' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
jo-arroyo committed Jan 20, 2023
2 parents cbcd099 + 6e07901 commit 9653628
Show file tree
Hide file tree
Showing 22 changed files with 211 additions and 46 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Added missing fields to InteractionRequiredAuthError #5566",
"packageName": "@azure/msal-common",
"email": "rginsburg@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Add support for custom http(s) agents #5472",
"packageName": "@azure/msal-node",
"email": "rginsburg@microsoft.com",
"dependentChangeType": "patch"
}
21 changes: 21 additions & 0 deletions lib/msal-common/CHANGELOG.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
{
"name": "@azure/msal-common",
"entries": [
{
"date": "Thu, 19 Jan 2023 23:50:24 GMT",
"tag": "@azure/msal-common_v9.1.1",
"version": "9.1.1",
"comments": {
"patch": [
{
"author": "joarroyo@microsoft.com",
"package": "@azure/msal-common",
"commit": "8e36aa8a2d086ee1156281b4e098af8a43e1c274",
"comment": "Update startMeasurement in PerformanceClient #5589"
},
{
"author": "kshabelko@microsoft.com",
"package": "@azure/msal-common",
"commit": "dd993f4346dd23f87a0d1a94af5389d392a4db7c",
"comment": "Add broker timeouts #5580"
}
]
}
},
{
"date": "Wed, 18 Jan 2023 00:33:04 GMT",
"tag": "@azure/msal-common_v9.1.0",
Expand Down
11 changes: 10 additions & 1 deletion lib/msal-common/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
# Change Log - @azure/msal-common

This log was last generated on Wed, 18 Jan 2023 00:33:04 GMT and should not be manually modified.
This log was last generated on Thu, 19 Jan 2023 23:50:24 GMT and should not be manually modified.

<!-- Start content -->

## 9.1.1

Thu, 19 Jan 2023 23:50:24 GMT

### Patches

- Update startMeasurement in PerformanceClient #5589 (joarroyo@microsoft.com)
- Add broker timeouts #5580 (kshabelko@microsoft.com)

## 9.1.0

Wed, 18 Jan 2023 00:33:04 GMT
Expand Down
4 changes: 2 additions & 2 deletions lib/msal-common/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/msal-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"type": "git",
"url": "https://github.com/AzureAD/microsoft-authentication-library-for-js.git"
},
"version": "9.1.0",
"version": "9.1.1",
"description": "Microsoft Authentication Library for js",
"keywords": [
"implicit",
Expand Down
31 changes: 28 additions & 3 deletions lib/msal-common/src/error/InteractionRequiredAuthError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Licensed under the MIT License.
*/

import { Constants } from "../utils/Constants";
import { AuthError } from "./AuthError";

/**
Expand Down Expand Up @@ -40,12 +41,36 @@ export const InteractionRequiredAuthErrorMessage = {
* Error thrown when user interaction is required.
*/
export class InteractionRequiredAuthError extends AuthError {
/**
* The time the error occured at
*/
timestamp: string;

constructor(errorCode?: string, errorMessage?: string, subError?: string) {
super(errorCode, errorMessage, subError);
this.name = "InteractionRequiredAuthError";
/**
* TraceId associated with the error
*/
traceId: string;

/**
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/claims-challenge.md
*
* A string with extra claims needed for the token request to succeed
* web site: redirect the user to the authorization page and set the extra claims
* web api: include the claims in the WWW-Authenticate header that are sent back to the client so that it knows to request a token with the extra claims
* desktop application or browser context: include the claims when acquiring the token interactively
* app to app context (client_credentials): include the claims in the AcquireTokenByClientCredential request
*/
claims: string;

constructor(errorCode?: string, errorMessage?: string, subError?: string, timestamp?: string, traceId?: string, correlationId?: string, claims?: string) {
super(errorCode, errorMessage, subError);
Object.setPrototypeOf(this, InteractionRequiredAuthError.prototype);

this.timestamp = timestamp || Constants.EMPTY_STRING;
this.traceId = traceId || Constants.EMPTY_STRING;
this.correlationId = correlationId || Constants.EMPTY_STRING;
this.claims = claims || Constants.EMPTY_STRING;
this.name = "InteractionRequiredAuthError";
}

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/msal-common/src/packageMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/* eslint-disable header/header */
export const name = "@azure/msal-common";
export const version = "9.1.0";
export const version = "9.1.1";
20 changes: 18 additions & 2 deletions lib/msal-common/src/response/ResponseHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,15 @@ export class ResponseHandler {
// Check for error
if (serverResponseHash.error || serverResponseHash.error_description || serverResponseHash.suberror) {
if (InteractionRequiredAuthError.isInteractionRequiredError(serverResponseHash.error, serverResponseHash.error_description, serverResponseHash.suberror)) {
throw new InteractionRequiredAuthError(serverResponseHash.error || Constants.EMPTY_STRING, serverResponseHash.error_description, serverResponseHash.suberror);
throw new InteractionRequiredAuthError(
serverResponseHash.error || Constants.EMPTY_STRING,
serverResponseHash.error_description,
serverResponseHash.suberror,
serverResponseHash.timestamp || Constants.EMPTY_STRING,
serverResponseHash.trace_id || Constants.EMPTY_STRING,
serverResponseHash.correlation_id || Constants.EMPTY_STRING,
serverResponseHash.claims || Constants.EMPTY_STRING,
);
}

throw new ServerError(serverResponseHash.error || Constants.EMPTY_STRING, serverResponseHash.error_description, serverResponseHash.suberror);
Expand All @@ -92,7 +100,15 @@ export class ResponseHandler {
// Check for error
if (serverResponse.error || serverResponse.error_description || serverResponse.suberror) {
if (InteractionRequiredAuthError.isInteractionRequiredError(serverResponse.error, serverResponse.error_description, serverResponse.suberror)) {
throw new InteractionRequiredAuthError(serverResponse.error, serverResponse.error_description, serverResponse.suberror);
throw new InteractionRequiredAuthError(
serverResponse.error,
serverResponse.error_description,
serverResponse.suberror,
serverResponse.timestamp || Constants.EMPTY_STRING,
serverResponse.trace_id || Constants.EMPTY_STRING,
serverResponse.correlation_id || Constants.EMPTY_STRING,
serverResponse.claims || Constants.EMPTY_STRING,
);
}

const errString = `${serverResponse.error_codes} - [${serverResponse.timestamp}]: ${serverResponse.error_description} - Correlation ID: ${serverResponse.correlation_id} - Trace ID: ${serverResponse.trace_id}`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export type ServerAuthorizationCodeResponse = {
error?: string,
error_description?: string;
suberror?: string;
timestamp?: string;
trace_id?: string;
correlation_id?: string;
claims?: string;
// Native Account ID
accountId?: string;
};
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ export type ServerAuthorizationTokenResponse = {
timestamp?: string;
trace_id?: string;
correlation_id?: string;
claims?: string;
};
17 changes: 13 additions & 4 deletions lib/msal-common/src/telemetry/performance/PerformanceClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,18 @@ export abstract class PerformanceClient implements IPerformanceClient {
this.logger.info(`PerformanceClient: No correlation id provided for ${measureName}, generating`, eventCorrelationId);
}

// Duplicate code to address spelling error will be removed at the next major version bump.
this.logger.trace(`PerformanceClient: Performance measurement started for ${measureName}`, eventCorrelationId);
const performanceMeasurement = this.startPerformanceMeasuremeant(measureName, eventCorrelationId);
performanceMeasurement.startMeasurement();
let validMeasurement: IPerformanceMeasurement;
const performanceMeasuremeant = this.startPerformanceMeasuremeant(measureName, eventCorrelationId);
if (performanceMeasuremeant.startMeasurement) {
performanceMeasuremeant.startMeasurement();
validMeasurement = performanceMeasuremeant;
} else {
const performanceMeasurement = this.startPerformanceMeasurement(measureName, eventCorrelationId);
performanceMeasurement.startMeasurement();
validMeasurement = performanceMeasurement;
}

const inProgressEvent: PerformanceEvent = {
eventId: this.generateId(),
Expand All @@ -142,7 +151,7 @@ export abstract class PerformanceClient implements IPerformanceClient {
appVersion: this.applicationTelemetry?.appVersion,
};
this.addStaticFields(staticFields, eventCorrelationId);
this.cacheMeasurement(inProgressEvent, performanceMeasurement);
this.cacheMeasurement(inProgressEvent, validMeasurement);

// Return the event and functions the caller can use to properly end/flush the measurement
return {
Expand Down Expand Up @@ -172,7 +181,7 @@ export abstract class PerformanceClient implements IPerformanceClient {
increment: (counters: Counters) => {
return this.increment(counters, inProgressEvent.correlationId);
},
measurement: performanceMeasurement,
measurement: validMeasurement,
event: inProgressEvent
};

Expand Down
42 changes: 40 additions & 2 deletions lib/msal-common/test/client/ClientCredentialClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { CredentialCache } from "../../src/cache/utils/CacheTypes";
import { CacheManager } from "../../src/cache/CacheManager";
import { ClientAuthError } from "../../src/error/ClientAuthError";
import { AuthenticationResult } from "../../src/response/AuthenticationResult";
import { AppTokenProviderResult, AuthToken, IAppTokenProvider } from "../../src";
import { AppTokenProviderResult, AuthToken, IAppTokenProvider, InteractionRequiredAuthError } from "../../src";

describe("ClientCredentialClient unit tests", () => {
afterEach(() => {
Expand All @@ -42,7 +42,7 @@ describe("ClientCredentialClient unit tests", () => {
expect(client instanceof BaseClient).toBe(true);
});
});

it("acquires a token", async () => {
sinon.stub(Authority.prototype, <any>"getEndpointMetadataFromNetwork").resolves(DEFAULT_OPENID_CONFIG_RESPONSE.body);
sinon.stub(ClientCredentialClient.prototype, <any>"executePostToTokenEndpoint").resolves(CONFIDENTIAL_CLIENT_AUTHENTICATION_RESULT);
Expand Down Expand Up @@ -79,6 +79,44 @@ describe("ClientCredentialClient unit tests", () => {
expect(returnVal.includes(`${AADServerParamKeys.X_MS_LIB_CAPABILITY}=${ThrottlingConstants.X_MS_LIB_CAPABILITY_VALUE}`)).toBe(true);
});

it("acquireToken's interactionRequiredAuthError error contains claims", async () => {
const errorResponse = {
error: "interaction_required",
error_description: "AADSTS50079: Due to a configuration change made by your administrator, or because you moved to a new location, you must enroll in multifactor authentication to access 'bf8d80f9-9098-4972-b203-500f535113b1'.\r\nTrace ID: b72a68c3-0926-4b8e-bc35-3150069c2800\r\nCorrelation ID: 73d656cf-54b1-4eb2-b429-26d8165a52d7\r\nTimestamp: 2017-05-01 22:43:20Z",
error_codes: [50079],
timestamp: "2017-05-01 22:43:20Z",
trace_id: "b72a68c3-0926-4b8e-bc35-3150069c2800",
correlation_id: "73d656cf-54b1-4eb2-b429-26d8165a52d7",
claims: "{\"access_token\":{\"polids\":{\"essential\":true,\"values\":[\"9ab03e19-ed42-4168-b6b7-7001fb3e933a\"]}}}",
};

sinon.stub(Authority.prototype, <any>"getEndpointMetadataFromNetwork").resolves(DEFAULT_OPENID_CONFIG_RESPONSE.body);
sinon.stub(ClientCredentialClient.prototype, <any>"executePostToTokenEndpoint").resolves({
headers: [],
body: errorResponse,
status: 400,
});

const config = await ClientTestUtils.createTestClientConfiguration();
const client = new ClientCredentialClient(config);
const clientCredentialRequest: CommonClientCredentialRequest = {
authority: TEST_CONFIG.validAuthority,
correlationId: TEST_CONFIG.CORRELATION_ID,
scopes: TEST_CONFIG.DEFAULT_GRAPH_SCOPE,
};

const interactionRequiredAuthError = new InteractionRequiredAuthError(
"interaction_required",
"AADSTS50079: Due to a configuration change made by your administrator, or because you moved to a new location, you must enroll in multifactor authentication to access 'bf8d80f9-9098-4972-b203-500f535113b1'.\r\nTrace ID: b72a68c3-0926-4b8e-bc35-3150069c2800\r\nCorrelation ID: 73d656cf-54b1-4eb2-b429-26d8165a52d7\r\nTimestamp: 2017-05-01 22:43:20Z",
"",
"2017-05-01 22:43:20Z",
"b72a68c3-0926-4b8e-bc35-3150069c2800",
"73d656cf-54b1-4eb2-b429-26d8165a52d7",
"{\"access_token\":{\"polids\":{\"essential\":true,\"values\":[\"9ab03e19-ed42-4168-b6b7-7001fb3e933a\"]}}}"
);
await expect(client.acquireToken(clientCredentialRequest)).rejects.toEqual(interactionRequiredAuthError);
});

// regression test for https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/5134
it("Multiple access tokens would match, but one of them has a Home Account ID of \"\"", async () => {
sinon.stub(Authority.prototype, <any>"getEndpointMetadataFromNetwork").resolves(DEFAULT_OPENID_CONFIG_RESPONSE.body);
Expand Down
10 changes: 9 additions & 1 deletion lib/msal-common/test/error/InteractionRequiredAuthError.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ describe("InteractionRequiredAuthError.ts Class Unit Tests", () => {
it("InteractionRequiredAuthError object can be created", () => {
const TEST_ERROR_CODE: string = "test";
const TEST_ERROR_MSG: string = "This is a test error";
const err: InteractionRequiredAuthError = new InteractionRequiredAuthError(TEST_ERROR_CODE, TEST_ERROR_MSG);
const TEST_ERROR_TIMESTAMP = "2017-05-01 22:43:20Z";
const TEST_ERROR_TRACE_ID = "b72a68c3-0926-4b8e-bc35-3150069c2800";
const TEST_ERROR_CORRELATION_ID = "73d656cf-54b1-4eb2-b429-26d8165a52d7";
const TEST_ERROR_CLAIMS = '{\"access_token\":{\"polids\":{\"essential\":true,\"values\":[\"9ab03e19-ed42-4168-b6b7-7001fb3e933a\"]}}}';
const err: InteractionRequiredAuthError = new InteractionRequiredAuthError(TEST_ERROR_CODE, TEST_ERROR_MSG, "N/A", TEST_ERROR_TIMESTAMP, TEST_ERROR_TRACE_ID, TEST_ERROR_CORRELATION_ID, TEST_ERROR_CLAIMS);

expect(err instanceof InteractionRequiredAuthError).toBe(true);
expect(err instanceof AuthError).toBe(true);
Expand All @@ -16,6 +20,10 @@ describe("InteractionRequiredAuthError.ts Class Unit Tests", () => {
expect(err.errorMessage).toBe(TEST_ERROR_MSG);
expect(err.message).toBe(`${TEST_ERROR_CODE}: ${TEST_ERROR_MSG}`);
expect(err.name).toBe("InteractionRequiredAuthError");
expect(err.timestamp).toBe(TEST_ERROR_TIMESTAMP);
expect(err.traceId).toBe(TEST_ERROR_TRACE_ID);
expect(err.correlationId).toBe(TEST_ERROR_CORRELATION_ID);
expect(err.claims).toBe(TEST_ERROR_CLAIMS);
expect(err.stack?.includes("InteractionRequiredAuthError.spec.ts")).toBe(true);
});

Expand Down
2 changes: 2 additions & 0 deletions lib/msal-node/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const msalConfig = {
logLevel: msal.LogLevel.Verbose,
},
proxyUrl: "",
customAgentOptions: {},
}
}

Expand Down Expand Up @@ -86,6 +87,7 @@ const msalInstance = new PublicClientApplication(msalConfig);
| `loggerOptions` | Config object for logger. | See [below](#logger-config-options). | See [below](#logger-config-options). |
| `NetworkClient` | Custom HTTP implementation | INetworkModule | [HttpClient.ts](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/src/network/HttpClient.ts) |
| `proxyUrl` | The URL of the proxy the app is running behind | string | Empty string `""` |
| `customAgentOptions` | Set of configurable options to set on a http(s) agent | Object - [NodeJS documentation on alloweable options](https://nodejs.org/docs/latest-v16.x/api/http.html#new-agentoptions) | Empty Object `{}` |

#### Logger Config Options
| Option | Description | Format | Default Value |
Expand Down
3 changes: 3 additions & 0 deletions lib/msal-node/docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ MSAL Node supports self-service sign-up in the auth code flow. Please see our do
### Why doesn't my app function correctly when it's running behind a proxy?
Developers can provide a `proxyUrl` string in the system config options as detailed [here](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md#system-config-options). Developers can also implement their own NetworkManager by instantiating an [INetworkModule](https://azuread.github.io/microsoft-authentication-library-for-js/ref/interfaces/_azure_msal_common.inetworkmodule.html) and building proxy support in it.

### How do I implement a custom http(s) agent in MSAL Node?
Developers can use a custom http(s) agent by providing a `customAgentOptions` object in the system config options as detailed [here](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md#system-config-options). Developers can also implement their own NetworkManager by instantiating an [INetworkModule](https://azuread.github.io/microsoft-authentication-library-for-js/ref/interfaces/_azure_msal_common.inetworkmodule.html) and building custom http(s) agent support in it.

## B2C

### How do I handle the password-reset user-flow?
Expand Down
14 changes: 9 additions & 5 deletions lib/msal-node/src/config/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
ApplicationTelemetry
} from "@azure/msal-common";
import { HttpClient } from "../network/HttpClient";
import { AgentOptions as httpAgentOptions } from "http";
import { AgentOptions as httpsAgentOptions } from "https";

/**
* - clientId - Client id of the application.
Expand Down Expand Up @@ -67,6 +69,7 @@ export type NodeSystemOptions = {
loggerOptions?: LoggerOptions;
networkClient?: INetworkModule;
proxyUrl?: string;
customAgentOptions?: httpAgentOptions | httpsAgentOptions;
};

export type NodeTelemetryOptions = {
Expand Down Expand Up @@ -124,6 +127,7 @@ const DEFAULT_SYSTEM_OPTIONS: Required<NodeSystemOptions> = {
loggerOptions: DEFAULT_LOGGER_OPTIONS,
networkClient: new HttpClient(),
proxyUrl: Constants.EMPTY_STRING,
customAgentOptions: {} as httpAgentOptions | httpsAgentOptions,
};

const DEFAULT_TELEMETRY_OPTIONS: Required<NodeTelemetryOptions> = {
Expand Down Expand Up @@ -157,16 +161,16 @@ export function buildAppConfiguration({
system,
telemetry
}: Configuration): NodeConfiguration {

const providedSystemOptions = {
...system,
loggerOptions: system?.loggerOptions || DEFAULT_LOGGER_OPTIONS
const systemOptions: Required<NodeSystemOptions> = {
...DEFAULT_SYSTEM_OPTIONS,
networkClient: system?.customAgentOptions ? new HttpClient(system.customAgentOptions as httpAgentOptions | httpsAgentOptions) : new HttpClient(),
loggerOptions: system?.loggerOptions || DEFAULT_LOGGER_OPTIONS,
};

return {
auth: { ...DEFAULT_AUTH_OPTIONS, ...auth },
cache: { ...DEFAULT_CACHE_OPTIONS, ...cache },
system: { ...DEFAULT_SYSTEM_OPTIONS, ...providedSystemOptions },
system: { ...systemOptions, ...system },
telemetry: { ...DEFAULT_TELEMETRY_OPTIONS, ...telemetry }
};
}

0 comments on commit 9653628

Please sign in to comment.