From 076ecb3408bef2a42258dd902ed75fd247b5c19f Mon Sep 17 00:00:00 2001 From: sameerag Date: Wed, 25 Mar 2020 22:12:01 -0700 Subject: [PATCH 01/11] Adding knownAuthorities() and B2CAuthority --- lib/msal-common/src/authority/Authority.ts | 2 +- .../src/authority/AuthorityFactory.ts | 25 ++-- lib/msal-common/src/authority/B2cAuthority.ts | 61 ++++++++ .../src/client/AuthorizationCodeFlow.ts | 131 ------------------ lib/msal-common/src/client/BaseClient.ts | 28 +++- .../AuthorizationClientConfiguration.ts | 1 + lib/msal-common/src/config/Configuration.ts | 1 + .../src/error/ClientConfigurationError.ts | 12 ++ lib/msal-common/src/utils/Constants.ts | 5 + 9 files changed, 123 insertions(+), 143 deletions(-) create mode 100644 lib/msal-common/src/authority/B2cAuthority.ts delete mode 100644 lib/msal-common/src/client/AuthorizationCodeFlow.ts diff --git a/lib/msal-common/src/authority/Authority.ts b/lib/msal-common/src/authority/Authority.ts index 37fc0c0511..a4683ce35c 100644 --- a/lib/msal-common/src/authority/Authority.ts +++ b/lib/msal-common/src/authority/Authority.ts @@ -110,7 +110,7 @@ export abstract class Authority { * @param urlString */ private replaceTenant(urlString: string): string { - return urlString.replace("{tenant}", this.tenant); + return urlString.replace(/{tenant}|{tenantid}/g, this.tenant); } /** diff --git a/lib/msal-common/src/authority/AuthorityFactory.ts b/lib/msal-common/src/authority/AuthorityFactory.ts index ced2aa4a90..baf613c970 100644 --- a/lib/msal-common/src/authority/AuthorityFactory.ts +++ b/lib/msal-common/src/authority/AuthorityFactory.ts @@ -10,6 +10,8 @@ import { ClientAuthError } from "./../error/ClientAuthError"; import { INetworkModule } from "./../network/INetworkModule"; import { StringUtils } from "./../utils/StringUtils"; import { UrlString } from "./../url/UrlString"; +import { B2CTrustedHostList } from "./../utils/Constants"; +import { B2cAuthority } from "./B2cAuthority"; export class AuthorityFactory { @@ -20,14 +22,14 @@ export class AuthorityFactory { const authorityUrl = new UrlString(authorityString); const components = authorityUrl.getUrlComponents(); const pathSegments = components.PathSegments; - switch (pathSegments[0]) { - case "tfp": - // tfp denotes a b2c url - return AuthorityType.B2C; - default: - // default authority is always AAD - return AuthorityType.Aad; - } + + if (pathSegments[0] === "adfs") + return AuthorityType.Adfs; + else if (Object.keys(B2CTrustedHostList).length) + return AuthorityType.B2C; + + // defaults to Aad + return AuthorityType.Aad; } /** @@ -45,8 +47,13 @@ export class AuthorityFactory { switch (type) { case AuthorityType.Aad: return new AadAuthority(authorityUrl, networkInterface); + case AuthorityType.B2C: + return new B2cAuthority(authorityUrl, networkInterface); + // TODO: Support ADFS here in a later PR default: - throw ClientAuthError.createInvalidAuthorityTypeError(`Given Url: ${authorityUrl}`); + throw ClientAuthError.createInvalidAuthorityTypeError( + `Given Url: ${authorityUrl}` + ); } } } diff --git a/lib/msal-common/src/authority/B2cAuthority.ts b/lib/msal-common/src/authority/B2cAuthority.ts new file mode 100644 index 0000000000..eb49ab8a24 --- /dev/null +++ b/lib/msal-common/src/authority/B2cAuthority.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ +import { Authority } from "./Authority"; +import { OpenIdConfigResponse } from "./OpenIdConfigResponse"; +import { AuthorityType } from "./AuthorityType"; +import { B2CTrustedHostList, Constants } from "../utils/Constants"; +import { INetworkModule } from "../network/INetworkModule"; +import { ClientConfigurationError } from "../error/ClientConfigurationError"; + +/** + * The AadAuthority class extends the Authority class and adds functionality specific to the Azure AD OAuth Authority. + */ +export class B2cAuthority extends Authority { + // Set authority type to AAD + public get authorityType(): AuthorityType { + return AuthorityType.Aad; + } + + // Default AAD Instance Discovery Endpoint + private get aadInstanceDiscoveryEndpointUrl(): string { + return `${Constants.AAD_INSTANCE_DISCOVERY_ENDPT}?api-version=1.0&authorization_endpoint=${this.canonicalAuthority}oauth2/v2.0/authorize`; + } + + public constructor(authority: string, networkInterface: INetworkModule) { + super(authority, networkInterface); + } + + /** + * Returns a promise which resolves to the OIDC endpoint + * Only responds with the endpoint + */ + public async getOpenIdConfigurationEndpointAsync(): Promise { + if ( + this.isInTrustedHostList( + this.canonicalAuthorityUrlComponents.HostNameAndPort + ) + ) { + return this.defaultOpenIdConfigurationEndpoint; + } + + // for custom domains in AAD where we query the service for the Instance discovery + const response = await this.networkInterface.sendGetRequestAsync< + OpenIdConfigResponse + >(this.aadInstanceDiscoveryEndpointUrl); + return response.tenant_discovery_endpoint; + } + + /** + * Checks to see if the host is in a list of trusted hosts + * @param {string} The host to look up + */ + public isInTrustedHostList(host: string): boolean { + if (!Object.keys(B2CTrustedHostList).length) { + throw ClientConfigurationError.createKnownAuthoritiesNotSetError(); + } + + return B2CTrustedHostList[host.toLowerCase()]; + } +} diff --git a/lib/msal-common/src/client/AuthorizationCodeFlow.ts b/lib/msal-common/src/client/AuthorizationCodeFlow.ts deleted file mode 100644 index 096d5bbced..0000000000 --- a/lib/msal-common/src/client/AuthorizationCodeFlow.ts +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -import { BaseClient } from "./BaseClient"; -import { - AuthorizationClientConfiguration, - buildAuthorizationClientConfiguration -} from "../config/AuthorizationClientConfiguration"; -import { AuthorizationCodeUrlRequest } from "../request/AuthorizationCodeUrlRequest"; -import { AuthorizationCodeRequest } from "../request/AuthorizationCodeRequest"; -import { AuthorityFactory } from "./../authority/AuthorityFactory"; -import { Authority } from "./../authority/Authority"; -import { Constants } from "./../utils/Constants"; -import { ClientAuthError } from "./../error/ClientAuthError"; -import { ServerParamsGenerator } from "../server/ServerParamsGenerator"; - -/** - * - * AuthorizationCodeFlow class - * - * Object instance which will construct requests to send to and handle responses - * from the Microsoft STS using the authorization code flow. - */ -export class AuthorizationCodeFlow extends BaseClient { - - // Application config - private clientConfig: AuthorizationClientConfiguration; - - constructor(configuration: AuthorizationClientConfiguration) { - // Implement base module - super({ - systemOptions: configuration.systemOptions, - loggerOptions: configuration.loggerOptions, - storageInterface: configuration.storageInterface, - networkInterface: configuration.networkInterface, - cryptoInterface: configuration.cryptoInterface - }); - // Implement defaults in config - this.clientConfig = buildAuthorizationClientConfiguration(configuration); - - // Initialize default authority instance - this.defaultAuthorityInstance = AuthorityFactory.createInstance( - this.clientConfig.auth.authority || Constants.DEFAULT_AUTHORITY, - this.networkClient - ); - } - - /** - * Creates a url for logging in a user. - * - scopes added by default: openid, profile and offline_access. - * - performs validation of the request parameters. - * - Including any SSO parameters (account, sid, login_hint) will short circuit the authentication and allow you to retrieve a code without interaction. - * - * @param request - */ - async getAuthCodeUrl(request: AuthorizationCodeUrlRequest): Promise { - const authority: Authority = await this.setAuthority(request && request.authority); - const urlMap: Map = request.generateAuthCodeUrlParams( - request, - this.clientConfig - ); - const url: string = ServerParamsGenerator.createUrl(urlMap, authority); - return url; - } - - /** - * API to acquire a token in exchange of 'authorization_code` acquired by the user in the first leg of the authorization_code_grant - * @param request - */ - async acquireTokenByCode(request: AuthorizationCodeRequest): Promise { - - const tokenEndpoint: Authority = await this.setAuthority(request && request.authority); - const acquiredTokenResponse = this.tokenRequest(tokenEndpoint, request); - return acquiredTokenResponse; - - // add response_handler here to send the response - } - - /** - * Create authority instance if not set already, resolve well-known-endpoint - * ADD discover authority instances - * @param authority - */ - private async setAuthority(authority: string): Promise { - // Initialize authority or use default, and perform discovery endpoint check. - const acquireTokenAuthority = authority - ? AuthorityFactory.createInstance(authority, this.networkClient) - : this.defaultAuthorityInstance; - - try { - await acquireTokenAuthority.resolveEndpointsAsync(); - } catch (e) { - throw ClientAuthError.createEndpointDiscoveryIncompleteError(e); - } - - return acquireTokenAuthority; - } - - /** - * - * @param tokenEndPoint - * @param body - * @param headers - */ - private async tokenRequest(tokenEndPoint: Authority, request: AuthorizationCodeRequest): Promise { - // generate the params - const urlMap: Map = request.generateAuthCodeParams( - request, - this.clientConfig - ); - - // generate body and headers for the POST request and perform token request - const headers: Map = new Map(); - let acquiredTokenResponse; - try { - acquiredTokenResponse = this.networkClient.sendPostRequestAsync( - tokenEndPoint.canonicalAuthority, - { - body: ServerParamsGenerator.createUrl(urlMap, tokenEndPoint), - headers: ServerParamsGenerator.createHeaders(headers) - } - ); - return acquiredTokenResponse; - } catch (error) { - console.log(error.response.data); - return error.response.data; - } - } -} diff --git a/lib/msal-common/src/client/BaseClient.ts b/lib/msal-common/src/client/BaseClient.ts index 3638bf3643..595c188136 100644 --- a/lib/msal-common/src/client/BaseClient.ts +++ b/lib/msal-common/src/client/BaseClient.ts @@ -12,8 +12,10 @@ import { Authority } from "../authority/Authority"; import { Logger } from "../logger/Logger"; import { AuthorityFactory } from "../authority/AuthorityFactory"; import { Constants } from "../utils/Constants"; -import {ClientAuthError} from "../error/ClientAuthError"; -import {ServerParamsGenerator} from "../server/ServerParamsGenerator"; +import { ClientAuthError } from "../error/ClientAuthError"; +import { ClientConfigurationError } from "../error/ClientConfigurationError"; +import { ServerParamsGenerator } from "../server/ServerParamsGenerator"; +import { B2CTrustedHostList } from "../utils/Constants"; /** * @hidden @@ -76,6 +78,8 @@ export abstract class BaseClient { // Set the network interface this.networkClient = this.config.networkInterface; + this.setKnownAuthorities(this.config.authOptions.knownAuthorities); + // Default authority instance. this.defaultAuthorityInstance = AuthorityFactory.createInstance( this.config.authOptions.authority || Constants.DEFAULT_AUTHORITY, @@ -112,4 +116,24 @@ export abstract class BaseClient { ServerParamsGenerator.addLibrarydataHeaders(headers); return headers; } + + /** + * @hidden + * @ignore + * Use when Authority is B2C and validateAuthority is set to True to provide list of allowed domains. + * @param authorityType + * @param validateAuthority + * @param knownAuthorities + */ + private setKnownAuthorities(knownAuthorities: Array): void { + if (!Object.keys(B2CTrustedHostList).length){ + if (!knownAuthorities.length) { + throw ClientConfigurationError.createKnownAuthoritiesNotSetError(); + } + + knownAuthorities.forEach(function(authority){ + B2CTrustedHostList[authority] = authority; + }); + } + } } diff --git a/lib/msal-common/src/config/AuthorizationClientConfiguration.ts b/lib/msal-common/src/config/AuthorizationClientConfiguration.ts index 187942522c..4aa6d781a0 100644 --- a/lib/msal-common/src/config/AuthorizationClientConfiguration.ts +++ b/lib/msal-common/src/config/AuthorizationClientConfiguration.ts @@ -15,6 +15,7 @@ export type AuthOptions = { clientId: string; redirectUri: string; authority?: string; + knownAuthorities?: string; }; /** diff --git a/lib/msal-common/src/config/Configuration.ts b/lib/msal-common/src/config/Configuration.ts index 9dfffe93ff..45749a3f57 100644 --- a/lib/msal-common/src/config/Configuration.ts +++ b/lib/msal-common/src/config/Configuration.ts @@ -39,6 +39,7 @@ export type Configuration = { export type AuthOptions = { clientId: string; authority?: string; + knownAuthorities?: Array }; /** diff --git a/lib/msal-common/src/error/ClientConfigurationError.ts b/lib/msal-common/src/error/ClientConfigurationError.ts index 5a23f6d439..aec31a329f 100644 --- a/lib/msal-common/src/error/ClientConfigurationError.ts +++ b/lib/msal-common/src/error/ClientConfigurationError.ts @@ -59,6 +59,10 @@ export const ClientConfigurationErrorMessage = { invalidCodeChallengeParams: { code: "one_of_code_challenge_code_challenge_method_params_missing", desc: "Both params: code_challenge and code_challenge_method are to be passed if to be sent in the request" + }, + b2cKnownAuthoritiesNotSet: { + code: "b2c_known_authorities_not_set", + desc: "Must set known authorities when validateAuthority is set to True and using B2C" } }; @@ -189,4 +193,12 @@ export class ClientConfigurationError extends ClientAuthError { ClientConfigurationErrorMessage.invalidCodeChallengeParams.desc ); } + + /** + * Throws an error when the user passes B2C authority and does not set knownAuthorities + */ + static createKnownAuthoritiesNotSetError(): ClientConfigurationError { + return new ClientConfigurationError(ClientConfigurationErrorMessage.b2cKnownAuthoritiesNotSet.code, + ClientConfigurationErrorMessage.b2cKnownAuthoritiesNotSet.desc); + } } diff --git a/lib/msal-common/src/utils/Constants.ts b/lib/msal-common/src/utils/Constants.ts index e5c510e8ea..b8f506f977 100644 --- a/lib/msal-common/src/utils/Constants.ts +++ b/lib/msal-common/src/utils/Constants.ts @@ -204,3 +204,8 @@ export enum GrantType { DEVICE_CODE_GRANT = "device_code" }; +/** + * Initialize B2CTrustedHostList + */ +export const B2CTrustedHostList = {}; + From c4fe6c0158600b7ed89ef3772d18f323092db6dd Mon Sep 17 00:00:00 2001 From: sameerag Date: Thu, 26 Mar 2020 16:02:06 -0700 Subject: [PATCH 02/11] addressing feedback and in sync with PR #1416 --- .../src/authority/AuthorityFactory.ts | 24 ++++++++++++- lib/msal-common/src/authority/B2cAuthority.ts | 36 ++++++------------- lib/msal-common/src/client/BaseClient.ts | 27 ++------------ .../src/error/ClientConfigurationError.ts | 12 +++++++ 4 files changed, 49 insertions(+), 50 deletions(-) diff --git a/lib/msal-common/src/authority/AuthorityFactory.ts b/lib/msal-common/src/authority/AuthorityFactory.ts index baf613c970..47cb1ebbf2 100644 --- a/lib/msal-common/src/authority/AuthorityFactory.ts +++ b/lib/msal-common/src/authority/AuthorityFactory.ts @@ -10,9 +10,13 @@ import { ClientAuthError } from "./../error/ClientAuthError"; import { INetworkModule } from "./../network/INetworkModule"; import { StringUtils } from "./../utils/StringUtils"; import { UrlString } from "./../url/UrlString"; -import { B2CTrustedHostList } from "./../utils/Constants"; import { B2cAuthority } from "./B2cAuthority"; +/** + * Initialize B2CTrustedHostList + */ +export const B2CTrustedHostList = {}; + export class AuthorityFactory { /** @@ -32,6 +36,24 @@ export class AuthorityFactory { return AuthorityType.Aad; } + /** + * @hidden + * @ignore + * Use when Authority is B2C is set to True to provide list of allowed domains. + * @param knownAuthorities + */ + public static setKnownAuthorities(knownAuthorities: Array): void { + if (!Object.keys(B2CTrustedHostList).length){ + if (!knownAuthorities.length) { + throw ClientConfigurationError.createKnownAuthoritiesNotSetError(); + } + + knownAuthorities.forEach(function(authority){ + B2CTrustedHostList[authority] = authority; + }); + } + } + /** * Create an authority object of the correct type based on the url * Performs basic authority validation - checks to see if the authority is of a valid type (eg aad, b2c) diff --git a/lib/msal-common/src/authority/B2cAuthority.ts b/lib/msal-common/src/authority/B2cAuthority.ts index eb49ab8a24..42a419e2a6 100644 --- a/lib/msal-common/src/authority/B2cAuthority.ts +++ b/lib/msal-common/src/authority/B2cAuthority.ts @@ -3,48 +3,34 @@ * Licensed under the MIT License. */ import { Authority } from "./Authority"; -import { OpenIdConfigResponse } from "./OpenIdConfigResponse"; -import { AuthorityType } from "./AuthorityType"; -import { B2CTrustedHostList, Constants } from "../utils/Constants"; +import { B2CTrustedHostList } from "./AuthorityFactory"; import { INetworkModule } from "../network/INetworkModule"; import { ClientConfigurationError } from "../error/ClientConfigurationError"; +import { AuthorityType } from './AuthorityType'; /** - * The AadAuthority class extends the Authority class and adds functionality specific to the Azure AD OAuth Authority. + * The B2cAuthority class extends the Authority class and adds functionality specific to the Azure AD OAuth Authority. */ export class B2cAuthority extends Authority { - // Set authority type to AAD + /** + * Set authority type to B2C + */ public get authorityType(): AuthorityType { - return AuthorityType.Aad; + return AuthorityType.B2C; } - - // Default AAD Instance Discovery Endpoint - private get aadInstanceDiscoveryEndpointUrl(): string { - return `${Constants.AAD_INSTANCE_DISCOVERY_ENDPT}?api-version=1.0&authorization_endpoint=${this.canonicalAuthority}oauth2/v2.0/authorize`; - } - - public constructor(authority: string, networkInterface: INetworkModule) { + public constructor(authority: string, networkInterface: INetworkModule) { super(authority, networkInterface); } /** - * Returns a promise which resolves to the OIDC endpoint - * Only responds with the endpoint + * Returns a promise with the TenantDiscoveryEndpoint */ public async getOpenIdConfigurationEndpointAsync(): Promise { - if ( - this.isInTrustedHostList( - this.canonicalAuthorityUrlComponents.HostNameAndPort - ) - ) { + if (this.isInTrustedHostList(this.canonicalAuthorityUrlComponents.HostNameAndPort)) { return this.defaultOpenIdConfigurationEndpoint; } - // for custom domains in AAD where we query the service for the Instance discovery - const response = await this.networkInterface.sendGetRequestAsync< - OpenIdConfigResponse - >(this.aadInstanceDiscoveryEndpointUrl); - return response.tenant_discovery_endpoint; + throw ClientConfigurationError.createUnsupportedAuthorityValidationError(); } /** diff --git a/lib/msal-common/src/client/BaseClient.ts b/lib/msal-common/src/client/BaseClient.ts index 3077fa903a..0e6157b636 100644 --- a/lib/msal-common/src/client/BaseClient.ts +++ b/lib/msal-common/src/client/BaseClient.ts @@ -14,8 +14,6 @@ import { AuthorityFactory } from "../authority/AuthorityFactory"; import { Constants } from "../utils/Constants"; import {ClientAuthError} from "../error/ClientAuthError"; import { RequestUtils } from "../utils/RequestUtils"; -import { B2CTrustedHostList } from "../utils/Constants"; -import { ClientConfigurationError } from "../error/ClientConfigurationError"; /** * @hidden @@ -78,9 +76,10 @@ export abstract class BaseClient { // Set the network interface this.networkClient = this.config.networkInterface; - this.setKnownAuthorities(this.config.authOptions.knownAuthorities); - // Default authority instance. + AuthorityFactory.setKnownAuthorities( + this.config.authOptions.knownAuthorities + ); this.defaultAuthorityInstance = AuthorityFactory.createInstance( this.config.authOptions.authority || Constants.DEFAULT_AUTHORITY, this.networkClient @@ -135,24 +134,4 @@ export abstract class BaseClient { headers: headers, }); } - - /** - * @hidden - * @ignore - * Use when Authority is B2C and validateAuthority is set to True to provide list of allowed domains. - * @param authorityType - * @param validateAuthority - * @param knownAuthorities - */ - private setKnownAuthorities(knownAuthorities: Array): void { - if (!Object.keys(B2CTrustedHostList).length){ - if (!knownAuthorities.length) { - throw ClientConfigurationError.createKnownAuthoritiesNotSetError(); - } - - knownAuthorities.forEach(function(authority){ - B2CTrustedHostList[authority] = authority; - }); - } - } } diff --git a/lib/msal-common/src/error/ClientConfigurationError.ts b/lib/msal-common/src/error/ClientConfigurationError.ts index aec31a329f..2ccbebd79e 100644 --- a/lib/msal-common/src/error/ClientConfigurationError.ts +++ b/lib/msal-common/src/error/ClientConfigurationError.ts @@ -63,6 +63,10 @@ export const ClientConfigurationErrorMessage = { b2cKnownAuthoritiesNotSet: { code: "b2c_known_authorities_not_set", desc: "Must set known authorities when validateAuthority is set to True and using B2C" + }, + unsupportedAuthorityValidation: { + code: "unsupported_authority_validation", + desc: "The authority validation is not supported for this authority type." } }; @@ -201,4 +205,12 @@ export class ClientConfigurationError extends ClientAuthError { return new ClientConfigurationError(ClientConfigurationErrorMessage.b2cKnownAuthoritiesNotSet.code, ClientConfigurationErrorMessage.b2cKnownAuthoritiesNotSet.desc); } + + /** + * Throws an error when the user passes an authority not set in knownAuthorities + */ + static createUnsupportedAuthorityValidationError(): ClientConfigurationError { + return new ClientConfigurationError(ClientConfigurationErrorMessage.unsupportedAuthorityValidation.code, + ClientConfigurationErrorMessage.unsupportedAuthorityValidation.desc); + } } From 7a9cefcaef43f238f67d485b966cb4bcdf63b1f6 Mon Sep 17 00:00:00 2001 From: sameerag Date: Thu, 26 Mar 2020 18:23:21 -0700 Subject: [PATCH 03/11] Update package.json --- samples/msal-node-auth-code/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/msal-node-auth-code/package.json b/samples/msal-node-auth-code/package.json index 7425b485b0..31337670e4 100644 --- a/samples/msal-node-auth-code/package.json +++ b/samples/msal-node-auth-code/package.json @@ -9,7 +9,7 @@ "author": "sameerag", "license": "MIT", "dependencies": { - "@azure/msal-node": "^0.0.1", + "@azure/msal-node": "^0.1.0", "express": "^4.17.1" } } From ae43cea294683f7aec1ce865a22702dc5d121c55 Mon Sep 17 00:00:00 2001 From: sameerag Date: Mon, 30 Mar 2020 22:42:27 -0700 Subject: [PATCH 04/11] addressing feedback --- lib/msal-common/src/authority/B2cAuthority.ts | 4 +-- lib/msal-common/src/config/Configuration.ts | 3 ++- lib/msal-common/src/utils/Constants.ts | 6 ----- lib/msal-node/src/network/HttpClient.ts | 27 ++++++++++++------- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/msal-common/src/authority/B2cAuthority.ts b/lib/msal-common/src/authority/B2cAuthority.ts index 42a419e2a6..71960373f5 100644 --- a/lib/msal-common/src/authority/B2cAuthority.ts +++ b/lib/msal-common/src/authority/B2cAuthority.ts @@ -6,7 +6,7 @@ import { Authority } from "./Authority"; import { B2CTrustedHostList } from "./AuthorityFactory"; import { INetworkModule } from "../network/INetworkModule"; import { ClientConfigurationError } from "../error/ClientConfigurationError"; -import { AuthorityType } from './AuthorityType'; +import { AuthorityType } from "./AuthorityType"; /** * The B2cAuthority class extends the Authority class and adds functionality specific to the Azure AD OAuth Authority. @@ -18,7 +18,7 @@ export class B2cAuthority extends Authority { public get authorityType(): AuthorityType { return AuthorityType.B2C; } - public constructor(authority: string, networkInterface: INetworkModule) { + public constructor(authority: string, networkInterface: INetworkModule) { super(authority, networkInterface); } diff --git a/lib/msal-common/src/config/Configuration.ts b/lib/msal-common/src/config/Configuration.ts index 45749a3f57..e8234b4686 100644 --- a/lib/msal-common/src/config/Configuration.ts +++ b/lib/msal-common/src/config/Configuration.ts @@ -76,7 +76,8 @@ export type LoggerOptions = { const DEFAULT_AUTH_OPTIONS: AuthOptions = { clientId: "", - authority: null + authority: null, + knownAuthorities: [] }; // Default module system options diff --git a/lib/msal-common/src/utils/Constants.ts b/lib/msal-common/src/utils/Constants.ts index a886dfb942..2ecbfa8955 100644 --- a/lib/msal-common/src/utils/Constants.ts +++ b/lib/msal-common/src/utils/Constants.ts @@ -207,9 +207,3 @@ export enum GrantType { REFRESH_TOKEN_GRANT = "refresh_token", DEVICE_CODE_GRANT = "device_code" }; - -/** - * Initialize B2CTrustedHostList - */ -export const B2CTrustedHostList = {}; - diff --git a/lib/msal-node/src/network/HttpClient.ts b/lib/msal-node/src/network/HttpClient.ts index 9368caecd7..9ed6c41990 100644 --- a/lib/msal-node/src/network/HttpClient.ts +++ b/lib/msal-node/src/network/HttpClient.ts @@ -3,7 +3,11 @@ * Licensed under the MIT License. */ -import { INetworkModule, NetworkRequestOptions, NetworkResponse } from '@azure/msal-common'; +import { + INetworkModule, + NetworkRequestOptions, + NetworkResponse, +} from '@azure/msal-common'; import { HttpMethod } from './../utils/Constants'; import axios, { AxiosRequestConfig } from 'axios'; @@ -11,7 +15,6 @@ import axios, { AxiosRequestConfig } from 'axios'; * This class implements the API for network requests. */ export class HttpClient implements INetworkModule { - /** * Http client for REST endpoints - Get request * @param url @@ -21,18 +24,20 @@ export class HttpClient implements INetworkModule { url: string, options?: NetworkRequestOptions ): Promise> { - const request: AxiosRequestConfig = { - method: HttpMethod.GET, - url: url, - headers: options && options.headers, - validateStatus: () => { return true } + const request: AxiosRequestConfig = { + method: HttpMethod.GET, + url: url, + headers: options && options.headers, + validateStatus: () => { + return true; + }, }; const response = await axios(request); return { headers: response.headers, body: response.data as T, - status: response.status + status: response.status, }; } @@ -50,14 +55,16 @@ export class HttpClient implements INetworkModule { url: url, data: (options && options.body) || '', headers: options && options.headers, - validateStatus: () => { return true } + validateStatus: () => { + return true; + }, }; const response = await axios(request); return { headers: response.headers, body: response.data as T, - status: response.status + status: response.status, }; } } From a66906fb4bb3cd8100131fa8553b157aee373697 Mon Sep 17 00:00:00 2001 From: sameerag Date: Thu, 2 Apr 2020 14:32:16 -0700 Subject: [PATCH 05/11] Fix a bug in AuthorityFactory.ts --- .../src/authority/AuthorityFactory.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/msal-common/src/authority/AuthorityFactory.ts b/lib/msal-common/src/authority/AuthorityFactory.ts index 47cb1ebbf2..0094a93809 100644 --- a/lib/msal-common/src/authority/AuthorityFactory.ts +++ b/lib/msal-common/src/authority/AuthorityFactory.ts @@ -27,11 +27,12 @@ export class AuthorityFactory { const components = authorityUrl.getUrlComponents(); const pathSegments = components.PathSegments; - if (pathSegments[0] === "adfs") + if (pathSegments[0] === "adfs") { return AuthorityType.Adfs; - else if (Object.keys(B2CTrustedHostList).length) + } + else if (Object.keys(B2CTrustedHostList).length) { return AuthorityType.B2C; - + } // defaults to Aad return AuthorityType.Aad; } @@ -43,12 +44,8 @@ export class AuthorityFactory { * @param knownAuthorities */ public static setKnownAuthorities(knownAuthorities: Array): void { - if (!Object.keys(B2CTrustedHostList).length){ - if (!knownAuthorities.length) { - throw ClientConfigurationError.createKnownAuthoritiesNotSetError(); - } - - knownAuthorities.forEach(function(authority){ + if (!Object.keys(B2CTrustedHostList).length && knownAuthorities) { + knownAuthorities.forEach(function (authority) { B2CTrustedHostList[authority] = authority; }); } @@ -65,6 +62,7 @@ export class AuthorityFactory { } const type = AuthorityFactory.detectAuthorityFromUrl(authorityUrl); + console.log(type.toString()); // Depending on above detection, create the right type. switch (type) { case AuthorityType.Aad: From 5a680a6c47f976e6f453c2f3a5b6ae9db9405c18 Mon Sep 17 00:00:00 2001 From: sameerag Date: Thu, 2 Apr 2020 19:04:59 -0700 Subject: [PATCH 06/11] merge msal-node-tests --- .../client/PublicClientApplication.spec.ts | 89 ++++++++++++------- lib/msal-node/test/network/HttpClient.spec.ts | 2 +- lib/msal-node/test/utils/TestConstants.ts | 36 ++++---- 3 files changed, 76 insertions(+), 51 deletions(-) diff --git a/lib/msal-node/test/client/PublicClientApplication.spec.ts b/lib/msal-node/test/client/PublicClientApplication.spec.ts index 4a93fb4632..a72473d56a 100644 --- a/lib/msal-node/test/client/PublicClientApplication.spec.ts +++ b/lib/msal-node/test/client/PublicClientApplication.spec.ts @@ -1,22 +1,43 @@ import { PublicClientApplication } from './../../src/client/PublicClientApplication'; -import {AuthorizationCodeRequest, ClientConfiguration} from './../../src/index'; -import { DeviceCodeRequest } from "@azure/msal-common/dist/src/request/DeviceCodeRequest"; -import {AuthorizationCodeClient, AuthorizationCodeUrlRequest, DeviceCodeClient} from "@azure/msal-common"; -import {AUTHENTICATION_RESULT, TEST_CONSTANTS} from "../utils/TestConstants"; +import { + AuthorizationCodeRequest, + ClientConfiguration, +} from './../../src/index'; +import { DeviceCodeRequest } from '@azure/msal-common/dist/src/request/DeviceCodeRequest'; +import { + AuthorizationCodeClient, + AuthorizationCodeUrlRequest, + DeviceCodeClient, +} from '@azure/msal-common'; +import { AUTHENTICATION_RESULT, TEST_CONSTANTS } from '../utils/TestConstants'; describe('PublicClientApplication', () => { - - jest.mock("@azure/msal-common"); - DeviceCodeClient.prototype.acquireToken = jest.fn(() => new Promise((resolve) => resolve(JSON.stringify(AUTHENTICATION_RESULT)))); - AuthorizationCodeClient.prototype.acquireToken = jest.fn(() => new Promise((resolve) => resolve(JSON.stringify(AUTHENTICATION_RESULT)))); - AuthorizationCodeClient.prototype.getAuthCodeUrl = jest.fn(() => new Promise((resolve) => resolve(TEST_CONSTANTS.AUTH_CODE_URL))); + jest.mock('@azure/msal-common'); + DeviceCodeClient.prototype.acquireToken = jest.fn( + () => + new Promise(resolve => + resolve(JSON.stringify(AUTHENTICATION_RESULT)) + ) + ); + AuthorizationCodeClient.prototype.acquireToken = jest.fn( + () => + new Promise(resolve => + resolve(JSON.stringify(AUTHENTICATION_RESULT)) + ) + ); + AuthorizationCodeClient.prototype.getAuthCodeUrl = jest.fn( + () => + new Promise(resolve => + resolve(TEST_CONSTANTS.AUTH_CODE_URL) + ) + ); test('exports a class', () => { const msalConfig: ClientConfiguration = { auth: { clientId: TEST_CONSTANTS.CLIENT_ID, authority: TEST_CONSTANTS.AUTHORITY, - } + }, }; const authApp = new PublicClientApplication(msalConfig); @@ -28,25 +49,29 @@ describe('PublicClientApplication', () => { auth: { clientId: TEST_CONSTANTS.CLIENT_ID, authority: TEST_CONSTANTS.AUTHORITY, - } + }, }; - jest.mock("@azure/msal-common"); - DeviceCodeClient.prototype.acquireToken = jest.fn(() => new Promise((resolve) => resolve(JSON.stringify(AUTHENTICATION_RESULT)))); + jest.mock('@azure/msal-common'); + DeviceCodeClient.prototype.acquireToken = jest.fn( + () => + new Promise(resolve => + resolve(JSON.stringify(AUTHENTICATION_RESULT)) + ) + ); const request: DeviceCodeRequest = { - deviceCodeCallback: response => {console.log(response)}, - scopes: TEST_CONSTANTS.DEFAULT_GRAPH_SCOPE + deviceCodeCallback: response => { + console.log(response); + }, + scopes: TEST_CONSTANTS.DEFAULT_GRAPH_SCOPE, }; - const authApp = new PublicClientApplication(msalConfig); - authApp.acquireTokenByDeviceCode(request) - .then((response) => { - - // expect(result).toBeInstanceOf(""); // TODO add check when response type is decided on - expect(response).toEqual(JSON.stringify(AUTHENTICATION_RESULT)); - }); + authApp.acquireTokenByDeviceCode(request).then(response => { + // expect(result).toBeInstanceOf(""); // TODO add check when response type is decided on + expect(response).toEqual(JSON.stringify(AUTHENTICATION_RESULT)); + }); }); test('acquireTokenByAuthorizationCode', () => { @@ -54,7 +79,7 @@ describe('PublicClientApplication', () => { auth: { clientId: TEST_CONSTANTS.CLIENT_ID, authority: TEST_CONSTANTS.AUTHORITY, - } + }, }; const request: AuthorizationCodeRequest = { @@ -64,11 +89,10 @@ describe('PublicClientApplication', () => { }; const authApp = new PublicClientApplication(msalConfig); - authApp.acquireTokenByCode(request) - .then((response) => { - // expect(result).toBeInstanceOf(""); // TODO add check when response type is decided on - expect(response).toEqual(JSON.stringify(AUTHENTICATION_RESULT)); - }); + authApp.acquireTokenByCode(request).then(response => { + // expect(result).toBeInstanceOf(""); // TODO add check when response type is decided on + expect(response).toEqual(JSON.stringify(AUTHENTICATION_RESULT)); + }); }); test('create AuthorizationCode URL', () => { @@ -76,7 +100,7 @@ describe('PublicClientApplication', () => { auth: { clientId: TEST_CONSTANTS.CLIENT_ID, authority: TEST_CONSTANTS.AUTHORITY, - } + }, }; const request: AuthorizationCodeUrlRequest = { @@ -85,9 +109,8 @@ describe('PublicClientApplication', () => { }; const authApp = new PublicClientApplication(msalConfig); - authApp.getAuthCodeUrl(request) - .then((response) => { - expect(response).toEqual(TEST_CONSTANTS.AUTH_CODE_URL); - }); + authApp.getAuthCodeUrl(request).then(response => { + expect(response).toEqual(TEST_CONSTANTS.AUTH_CODE_URL); + }); }); }); diff --git a/lib/msal-node/test/network/HttpClient.spec.ts b/lib/msal-node/test/network/HttpClient.spec.ts index 90821e02a1..fc39a900e7 100644 --- a/lib/msal-node/test/network/HttpClient.spec.ts +++ b/lib/msal-node/test/network/HttpClient.spec.ts @@ -1,6 +1,6 @@ import { HttpClient } from '../../src/network/HttpClient'; import axios, { AxiosResponse } from 'axios'; -import { mocked } from "ts-jest"; //<-- This allows to mock results +import { mocked } from 'ts-jest'; //<-- This allows to mock results jest.mock('axios'); diff --git a/lib/msal-node/test/utils/TestConstants.ts b/lib/msal-node/test/utils/TestConstants.ts index 1a61ccec4f..f0764e7611 100644 --- a/lib/msal-node/test/utils/TestConstants.ts +++ b/lib/msal-node/test/utils/TestConstants.ts @@ -3,26 +3,28 @@ */ export const TEST_CONSTANTS = { - CLIENT_ID: "b41a6fbb-c728-4e03-aa59-d25b0fd383b6", - AUTHORITY: "https://login.microsoftonline.com/TenantId", - REDIRECT_URI: "http://localhost:8080", - DEFAULT_GRAPH_SCOPE: ["user.read"], - AUTHORIZATION_CODE: "0.ASgAqPq4kJXMDkamGO53C-4XWVm3ypmrKgtCkdhePY1PBjsoAJg.AQABAAIAAAAm-06blBE1TpVMil8KPQ41DOje1jDj1oK3KxTXGKg89VjLYJi71gx_npOoxVfC7X49MqOX7IltTJOilUId-IAHndHXlfWzoSGq3GUmwAOLMisftceBRtq3YBsvHX7giiuSZXJgpgu03uf3V2h5Z3GJNpnSXT1f7iVFuRvGh1-jqjWxKs2un8AS5rhti1ym1zxkeicKT43va5jQeHVUlTQo69llnwQJ3iKmKLDVq_Q25Au4EQjYaeEx6TP5IZSqPPm7x0bynmjE8cqR5r4ySP4wH8fjnxlLySrUEZObk2VgREB1AdH6-xKIa04EnJEj9dUgTwiFvQumkuHHetFOgH7ep_9diFOdAOQLUK8C9N4Prlj0JiOcgn6l0xYd5Q9691Ylw8UfifLwq_B7f30mMLN64_XgoBY9K9CR1L4EC1kPPwIhVv3m6xmbhXZ3efx-A-bbV2SYcO4D4ZlnQztHzie_GUlredtsdEMAOE3-jaMJs7i2yYMuIEEtRcHIjV_WscVooCDdKmVncHOObWhNUSdULAejBr3pFs0v3QO_xZ269eLu5Z0qHzCZ_EPg2aL-ERz-rpgdclQ_H_KnEtMsC4F1RgAnDjVmSRKJZZdnNLfKSX_Wd40t_nuo4kjN2cSt8QzzeL533zIZ4CxthOsC4HH2RcUZDIgHdLDLT2ukg-Osc6J9URpZP-IUpdjXg_uwbkHEjrXDMBMo2pmCqaWbMJKo5Lr7CrystifnDITXzZmmOah8HV83Xyb6EP8Gno6JRuaG80j8BKDWyb1Yof4rnLI1kZ59n_t2d0LnRBXz50PdWCWX6vtkg-kAV-bGJQr45XDSKBSv0Q_fVsdLMk24NacUZcF5ujUtqv__Bv-wATzCHWlbUDGHC8nHEi84PcYAjSsgAA", - AUTH_CODE_URL: "https://login.microsoftonline.com/TenantId/oauth2.0/v2.0/authorize?client_id=b41a6fbb-c728-4e03-aa59-d25b0fd383b6&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2F8080%2F&response_mode=query&scope=user.read%20openid%20profile%20offline_access" + CLIENT_ID: 'b41a6fbb-c728-4e03-aa59-d25b0fd383b6', + AUTHORITY: 'https://login.microsoftonline.com/TenantId', + REDIRECT_URI: 'http://localhost:8080', + DEFAULT_GRAPH_SCOPE: ['user.read'], + AUTHORIZATION_CODE: + '0.ASgAqPq4kJXMDkamGO53C-4XWVm3ypmrKgtCkdhePY1PBjsoAJg.AQABAAIAAAAm-06blBE1TpVMil8KPQ41DOje1jDj1oK3KxTXGKg89VjLYJi71gx_npOoxVfC7X49MqOX7IltTJOilUId-IAHndHXlfWzoSGq3GUmwAOLMisftceBRtq3YBsvHX7giiuSZXJgpgu03uf3V2h5Z3GJNpnSXT1f7iVFuRvGh1-jqjWxKs2un8AS5rhti1ym1zxkeicKT43va5jQeHVUlTQo69llnwQJ3iKmKLDVq_Q25Au4EQjYaeEx6TP5IZSqPPm7x0bynmjE8cqR5r4ySP4wH8fjnxlLySrUEZObk2VgREB1AdH6-xKIa04EnJEj9dUgTwiFvQumkuHHetFOgH7ep_9diFOdAOQLUK8C9N4Prlj0JiOcgn6l0xYd5Q9691Ylw8UfifLwq_B7f30mMLN64_XgoBY9K9CR1L4EC1kPPwIhVv3m6xmbhXZ3efx-A-bbV2SYcO4D4ZlnQztHzie_GUlredtsdEMAOE3-jaMJs7i2yYMuIEEtRcHIjV_WscVooCDdKmVncHOObWhNUSdULAejBr3pFs0v3QO_xZ269eLu5Z0qHzCZ_EPg2aL-ERz-rpgdclQ_H_KnEtMsC4F1RgAnDjVmSRKJZZdnNLfKSX_Wd40t_nuo4kjN2cSt8QzzeL533zIZ4CxthOsC4HH2RcUZDIgHdLDLT2ukg-Osc6J9URpZP-IUpdjXg_uwbkHEjrXDMBMo2pmCqaWbMJKo5Lr7CrystifnDITXzZmmOah8HV83Xyb6EP8Gno6JRuaG80j8BKDWyb1Yof4rnLI1kZ59n_t2d0LnRBXz50PdWCWX6vtkg-kAV-bGJQr45XDSKBSv0Q_fVsdLMk24NacUZcF5ujUtqv__Bv-wATzCHWlbUDGHC8nHEi84PcYAjSsgAA', + AUTH_CODE_URL: + 'https://login.microsoftonline.com/TenantId/oauth2.0/v2.0/authorize?client_id=b41a6fbb-c728-4e03-aa59-d25b0fd383b6&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2F8080%2F&response_mode=query&scope=user.read%20openid%20profile%20offline_access', }; export const AUTHENTICATION_RESULT = { status: 200, body: { - "token_type": "Bearer", - "scope": "openid profile User.Read email", - "expires_in": 3599, - "ext_expires_in": 3599, - "access_token": "eyJ0eXAiOiJKV1QiLCJub25jZSI6Il9MWUUtN1ZYVkxKUmg3R0kzVDJVVDFoYTJDTi1heVlFRV9fT0RleTBKT3ciLCJhbGciOiJSUzI1NiIsIng1dCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSIsImtpZCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSJ9.eyJhdWQiOiIwMDAwMDAwMy0wMDAwLTAwMDAtYzAwMC0wMDAwMDAwMDAwMDAiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC85MGI4ZmFhOC1jYzk1LTQ2MGUtYTYxOC1lZTc3MGJlZTE3NTkvIiwiaWF0IjoxNTg1MTU1MzkzLCJuYmYiOjE1ODUxNTUzOTMsImV4cCI6MTU4NTE1OTI5MywiYWNjdCI6MCwiYWNyIjoiMSIsImFpbyI6IkFXUUFtLzhQQUFBQWtBeWt4ODRpNjk5eGMwTFNVMkh5UG1UT3VHeHpZY1hod3k1YnZwbTkxRkMyVzZpOUZyYzhETHA0emQ5cEhaVnREK0tCZlN6R1RoMU1pT2xOZVc0RzNoRjFkWE9CVGd1b0lGYW0wd1RHWGh2RWZIaWkvYTJVelU0RXAzTjduWnFZIiwiYWx0c2VjaWQiOiI1OjoxMDAzM0ZGRkE3QzRCQzI4IiwiYW1yIjpbIndpYSJdLCJhcHBfZGlzcGxheW5hbWUiOiJOb2RlQXV0aENvZGUiLCJhcHBpZCI6Ijk5Y2FiNzU5LTJhYWItNDIwYi05MWQ4LTVlM2Q4ZDRmMDYzYiIsImFwcGlkYWNyIjoiMCIsImVtYWlsIjoic2Fnb256YWxAbWljcm9zb2Z0LmNvbSIsImZhbWlseV9uYW1lIjoiR29uemFsZXoiLCJnaXZlbl9uYW1lIjoic2Fnb256YWxAbWljcm9zb2Z0LmNvbSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzcyZjk4OGJmLTg2ZjEtNDFhZi05MWFiLTJkN2NkMDExZGI0Ny8iLCJpcGFkZHIiOiIxMzEuMTA3LjE0Ny4xMjUiLCJuYW1lIjoic2Fnb256YWxAbWljcm9zb2Z0LmNvbSBHb256YWxleiIsIm9pZCI6ImM0ZDNmNjk0LWVmNzQtNDZkYS1hNjU3LWE4NjJhNWJjYzQzOSIsInBsYXRmIjoiMyIsInB1aWQiOiIxMDAzMjAwMDM1NUQwNkExIiwic2NwIjoib3BlbmlkIHByb2ZpbGUgVXNlci5SZWFkIGVtYWlsIiwic2lnbmluX3N0YXRlIjpbImttc2kiXSwic3ViIjoiLTZBOHp3OW1rbEtuUVIxSldvTGZyWGk5ckRFcjBod1hBbzhnSTlCQnBINCIsInRpZCI6IjkwYjhmYWE4LWNjOTUtNDYwZS1hNjE4LWVlNzcwYmVlMTc1OSIsInVuaXF1ZV9uYW1lIjoic2Fnb256YWxAbWljcm9zb2Z0LmNvbSIsInV0aSI6Ikhfc0lubDRTcjAyY196NmphaGlhQUEiLCJ2ZXIiOiIxLjAiLCJ3aWRzIjpbIjYyZTkwMzk0LTY5ZjUtNDIzNy05MTkwLTAxMjE3NzE0NWUxMCJdLCJ4bXNfc3QiOnsic3ViIjoienh3QTlOMXBFM0pVekwtWUlDTmxoZG9TYTVNbWNveE5tVTk4X1N0OUliMCJ9LCJ4bXNfdGNkdCI6MTU0NTUyMDc2OH0.ZGUvk5G6IvtUVFFFqldzJrsJLlxePaV6FwMNAm6MPqtBO3tSTmErCvg3KEEUnuh4WowDgOJVACTvtlFn6infvdIQdaCK2THZvmpCzHvFX2x7yD3H1KkD23ylmETIX4YWDfVbzjm5coSOzdhjX7-G7KBHQH6DDpCNX3mR7kBxRrcYZvOzBEZZQnDb77cmssUT-ZaImprDlgFlCe4355LjmYT8GruMzhHsC_Yb9gspkl0Tl0rLmJ95tS7xvQtTw2tyQ-AGDmxKaIvK88RmS5RCAlo0aH1vy8rsQZ8dmygyn4h9n-0afJ_MBdfwGlP4Q6hO_Buf8ydZHuRLTn7EbXrfRg", - "refresh_token": "0.ASgAqPq4kJXMDkamGO53C-4XWVm3ypmrKgtCkdhePY1PBjsoAJg.AQABAAAAAAAm-06blBE1TpVMil8KPQ41wKTIQA_xfFsGu4Kcj8Vl_xwPdc9zNkAWI9UC-ODdtiCsVcFov0tEWrmd3fsbiL12B8HhRpahiit6Ee81RH0Z1SGe7yOr5wg8bcFYbcNGQHKwtleRoe5Ti-trn2oirb8VSpuaoBU791iwwCBzyjFH7rRJosRRAxdBSw9jNcNYc2VE6zc8Dd_1svKWpX5lfk24A_oUQ8Ghh_Hp-471qiiak7_qF3bqoAnFQ56HsMeCWz9LMPEVUt1pXi3-rzepM77ykJ157tJic1wO9LyHEhx0Xc3WHakAzE_VK075PqRMraQiYrR3k9XQbTv_7ezPvXD_f1GibIdyoRr5-cnqYKO8t0nZFksWei0Bfgo-bQT1u3bUZcnDn26E7zOKxighnwUnuob-RkeGNsay8Ac2UDMyxuVzMaR1Al84Cchb8_0Yte_MtkyUMG92PT0ShiM3EFkZHT30KaWZdMZGrEFsA_PGeEOHYZYV9rycPtZm9zH3ydlm7ruwlnOiEmXrh-VqprHpzoGj-HSO4PXXvNrMrXHTlAhuCtSc15leMTwI8aqrogAtYA-zUnMCiS-Atm6fG4wvW2_aO5Lp1FjI3rQT-OO_JWW27wMNocCYS_7oQB6A4vW2gWsVBMJU2frZ9EwmaApnUOazCQ-6Mtt7KX8uCekBftdrYAURBiMbrdzZEzyCLnarKk4j8dVM9LiGm0mWH-wN37xx_IH0HcZKkwtAskWROzc0yXC_6Du_IZG-Qo3sWsgMzm9G9iNjunvLo-ArTCPgfXWSahqrO-J4QMlmeMeZNn9yNFIqUDPirtU4lZJIoCBURr-3WW4bSxE1KWkH6DFP2vz9KjXEIrvwG1ElAmpEnxwn6ECOb24OYO6bdprwEHhExGDRwp8upPzpQxY9sBPMu0pcvej3my7BdvAJPFn2xCBnSiqrZ4XUs-noNdsyV7IlTpcUXcc4K7sgUPB4DH0Is5qvTRbK1n2MG4-YtVODrMX2Me68TYyEtlOy8l0OFaD4ytij3SrVrncPfZGomxfOhRuzXADOMo6QCDZKEKmArV60lhO0QSYaqw92y8DQLntrJtrAFPIzk_M2CU55Tm9opZAQIBJFXMdia_J-o83t9iAA", - "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSJ9.eyJhdWQiOiI5OWNhYjc1OS0yYWFiLTQyMGItOTFkOC01ZTNkOGQ0ZjA2M2IiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vOTBiOGZhYTgtY2M5NS00NjBlLWE2MTgtZWU3NzBiZWUxNzU5L3YyLjAiLCJpYXQiOjE1ODUxNTUzOTMsIm5iZiI6MTU4NTE1NTM5MywiZXhwIjoxNTg1MTU5MjkzLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMWRiNDcvIiwibmFtZSI6InNhZ29uemFsQG1pY3Jvc29mdC5jb20gR29uemFsZXoiLCJvaWQiOiJjNGQzZjY5NC1lZjc0LTQ2ZGEtYTY1Ny1hODYyYTViY2M0MzkiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzYWdvbnphbEBtaWNyb3NvZnQuY29tIiwic3ViIjoienh3QTlOMXBFM0pVekwtWUlDTmxoZG9TYTVNbWNveE5tVTk4X1N0OUliMCIsInRpZCI6IjkwYjhmYWE4LWNjOTUtNDYwZS1hNjE4LWVlNzcwYmVlMTc1OSIsInV0aSI6Ikhfc0lubDRTcjAyY196NmphaGlhQUEiLCJ2ZXIiOiIyLjAifQ.WliASidSbhPmfnazz0y8JLreOHzecO9EI39DfYv2Vxj_R-WcMcrPgZZvfK_XBV9oTGPGtep3I2U0Etqcd7RNBdnYGFzM3i8IQM247r4K0TpM5n_zfr1n8iROc86uUvduSYUMMCBM_21xsboNnLfNUxbCc2Mp-C-xRfjXxWNHhcJKTSI-BCroFwL6402XLCWNS351QXeq1h_El9vLdf6NpSDhq5IV0CvRn32T-N3VrYKG6TURomfcvqQWeM5vDRv04jqn7HJRzkVGofq4PVExcd-XUzkmoDkKr5X7GxcO0FB-ROLb9PkS6Rvi8HlaGH9EcI5EkHCjLuZ9mV5jpyxRSQ" - } + token_type: 'Bearer', + scope: 'openid profile User.Read email', + expires_in: 3599, + ext_expires_in: 3599, + access_token: + 'eyJ0eXAiOiJKV1QiLCJub25jZSI6Il9MWUUtN1ZYVkxKUmg3R0kzVDJVVDFoYTJDTi1heVlFRV9fT0RleTBKT3ciLCJhbGciOiJSUzI1NiIsIng1dCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSIsImtpZCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSJ9.eyJhdWQiOiIwMDAwMDAwMy0wMDAwLTAwMDAtYzAwMC0wMDAwMDAwMDAwMDAiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC85MGI4ZmFhOC1jYzk1LTQ2MGUtYTYxOC1lZTc3MGJlZTE3NTkvIiwiaWF0IjoxNTg1MTU1MzkzLCJuYmYiOjE1ODUxNTUzOTMsImV4cCI6MTU4NTE1OTI5MywiYWNjdCI6MCwiYWNyIjoiMSIsImFpbyI6IkFXUUFtLzhQQUFBQWtBeWt4ODRpNjk5eGMwTFNVMkh5UG1UT3VHeHpZY1hod3k1YnZwbTkxRkMyVzZpOUZyYzhETHA0emQ5cEhaVnREK0tCZlN6R1RoMU1pT2xOZVc0RzNoRjFkWE9CVGd1b0lGYW0wd1RHWGh2RWZIaWkvYTJVelU0RXAzTjduWnFZIiwiYWx0c2VjaWQiOiI1OjoxMDAzM0ZGRkE3QzRCQzI4IiwiYW1yIjpbIndpYSJdLCJhcHBfZGlzcGxheW5hbWUiOiJOb2RlQXV0aENvZGUiLCJhcHBpZCI6Ijk5Y2FiNzU5LTJhYWItNDIwYi05MWQ4LTVlM2Q4ZDRmMDYzYiIsImFwcGlkYWNyIjoiMCIsImVtYWlsIjoic2Fnb256YWxAbWljcm9zb2Z0LmNvbSIsImZhbWlseV9uYW1lIjoiR29uemFsZXoiLCJnaXZlbl9uYW1lIjoic2Fnb256YWxAbWljcm9zb2Z0LmNvbSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzcyZjk4OGJmLTg2ZjEtNDFhZi05MWFiLTJkN2NkMDExZGI0Ny8iLCJpcGFkZHIiOiIxMzEuMTA3LjE0Ny4xMjUiLCJuYW1lIjoic2Fnb256YWxAbWljcm9zb2Z0LmNvbSBHb256YWxleiIsIm9pZCI6ImM0ZDNmNjk0LWVmNzQtNDZkYS1hNjU3LWE4NjJhNWJjYzQzOSIsInBsYXRmIjoiMyIsInB1aWQiOiIxMDAzMjAwMDM1NUQwNkExIiwic2NwIjoib3BlbmlkIHByb2ZpbGUgVXNlci5SZWFkIGVtYWlsIiwic2lnbmluX3N0YXRlIjpbImttc2kiXSwic3ViIjoiLTZBOHp3OW1rbEtuUVIxSldvTGZyWGk5ckRFcjBod1hBbzhnSTlCQnBINCIsInRpZCI6IjkwYjhmYWE4LWNjOTUtNDYwZS1hNjE4LWVlNzcwYmVlMTc1OSIsInVuaXF1ZV9uYW1lIjoic2Fnb256YWxAbWljcm9zb2Z0LmNvbSIsInV0aSI6Ikhfc0lubDRTcjAyY196NmphaGlhQUEiLCJ2ZXIiOiIxLjAiLCJ3aWRzIjpbIjYyZTkwMzk0LTY5ZjUtNDIzNy05MTkwLTAxMjE3NzE0NWUxMCJdLCJ4bXNfc3QiOnsic3ViIjoienh3QTlOMXBFM0pVekwtWUlDTmxoZG9TYTVNbWNveE5tVTk4X1N0OUliMCJ9LCJ4bXNfdGNkdCI6MTU0NTUyMDc2OH0.ZGUvk5G6IvtUVFFFqldzJrsJLlxePaV6FwMNAm6MPqtBO3tSTmErCvg3KEEUnuh4WowDgOJVACTvtlFn6infvdIQdaCK2THZvmpCzHvFX2x7yD3H1KkD23ylmETIX4YWDfVbzjm5coSOzdhjX7-G7KBHQH6DDpCNX3mR7kBxRrcYZvOzBEZZQnDb77cmssUT-ZaImprDlgFlCe4355LjmYT8GruMzhHsC_Yb9gspkl0Tl0rLmJ95tS7xvQtTw2tyQ-AGDmxKaIvK88RmS5RCAlo0aH1vy8rsQZ8dmygyn4h9n-0afJ_MBdfwGlP4Q6hO_Buf8ydZHuRLTn7EbXrfRg', + refresh_token: + '0.ASgAqPq4kJXMDkamGO53C-4XWVm3ypmrKgtCkdhePY1PBjsoAJg.AQABAAAAAAAm-06blBE1TpVMil8KPQ41wKTIQA_xfFsGu4Kcj8Vl_xwPdc9zNkAWI9UC-ODdtiCsVcFov0tEWrmd3fsbiL12B8HhRpahiit6Ee81RH0Z1SGe7yOr5wg8bcFYbcNGQHKwtleRoe5Ti-trn2oirb8VSpuaoBU791iwwCBzyjFH7rRJosRRAxdBSw9jNcNYc2VE6zc8Dd_1svKWpX5lfk24A_oUQ8Ghh_Hp-471qiiak7_qF3bqoAnFQ56HsMeCWz9LMPEVUt1pXi3-rzepM77ykJ157tJic1wO9LyHEhx0Xc3WHakAzE_VK075PqRMraQiYrR3k9XQbTv_7ezPvXD_f1GibIdyoRr5-cnqYKO8t0nZFksWei0Bfgo-bQT1u3bUZcnDn26E7zOKxighnwUnuob-RkeGNsay8Ac2UDMyxuVzMaR1Al84Cchb8_0Yte_MtkyUMG92PT0ShiM3EFkZHT30KaWZdMZGrEFsA_PGeEOHYZYV9rycPtZm9zH3ydlm7ruwlnOiEmXrh-VqprHpzoGj-HSO4PXXvNrMrXHTlAhuCtSc15leMTwI8aqrogAtYA-zUnMCiS-Atm6fG4wvW2_aO5Lp1FjI3rQT-OO_JWW27wMNocCYS_7oQB6A4vW2gWsVBMJU2frZ9EwmaApnUOazCQ-6Mtt7KX8uCekBftdrYAURBiMbrdzZEzyCLnarKk4j8dVM9LiGm0mWH-wN37xx_IH0HcZKkwtAskWROzc0yXC_6Du_IZG-Qo3sWsgMzm9G9iNjunvLo-ArTCPgfXWSahqrO-J4QMlmeMeZNn9yNFIqUDPirtU4lZJIoCBURr-3WW4bSxE1KWkH6DFP2vz9KjXEIrvwG1ElAmpEnxwn6ECOb24OYO6bdprwEHhExGDRwp8upPzpQxY9sBPMu0pcvej3my7BdvAJPFn2xCBnSiqrZ4XUs-noNdsyV7IlTpcUXcc4K7sgUPB4DH0Is5qvTRbK1n2MG4-YtVODrMX2Me68TYyEtlOy8l0OFaD4ytij3SrVrncPfZGomxfOhRuzXADOMo6QCDZKEKmArV60lhO0QSYaqw92y8DQLntrJtrAFPIzk_M2CU55Tm9opZAQIBJFXMdia_J-o83t9iAA', + id_token: + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSJ9.eyJhdWQiOiI5OWNhYjc1OS0yYWFiLTQyMGItOTFkOC01ZTNkOGQ0ZjA2M2IiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vOTBiOGZhYTgtY2M5NS00NjBlLWE2MTgtZWU3NzBiZWUxNzU5L3YyLjAiLCJpYXQiOjE1ODUxNTUzOTMsIm5iZiI6MTU4NTE1NTM5MywiZXhwIjoxNTg1MTU5MjkzLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMWRiNDcvIiwibmFtZSI6InNhZ29uemFsQG1pY3Jvc29mdC5jb20gR29uemFsZXoiLCJvaWQiOiJjNGQzZjY5NC1lZjc0LTQ2ZGEtYTY1Ny1hODYyYTViY2M0MzkiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzYWdvbnphbEBtaWNyb3NvZnQuY29tIiwic3ViIjoienh3QTlOMXBFM0pVekwtWUlDTmxoZG9TYTVNbWNveE5tVTk4X1N0OUliMCIsInRpZCI6IjkwYjhmYWE4LWNjOTUtNDYwZS1hNjE4LWVlNzcwYmVlMTc1OSIsInV0aSI6Ikhfc0lubDRTcjAyY196NmphaGlhQUEiLCJ2ZXIiOiIyLjAifQ.WliASidSbhPmfnazz0y8JLreOHzecO9EI39DfYv2Vxj_R-WcMcrPgZZvfK_XBV9oTGPGtep3I2U0Etqcd7RNBdnYGFzM3i8IQM247r4K0TpM5n_zfr1n8iROc86uUvduSYUMMCBM_21xsboNnLfNUxbCc2Mp-C-xRfjXxWNHhcJKTSI-BCroFwL6402XLCWNS351QXeq1h_El9vLdf6NpSDhq5IV0CvRn32T-N3VrYKG6TURomfcvqQWeM5vDRv04jqn7HJRzkVGofq4PVExcd-XUzkmoDkKr5X7GxcO0FB-ROLb9PkS6Rvi8HlaGH9EcI5EkHCjLuZ9mV5jpyxRSQ', + }, }; - - - From 80b2e1d100278a01805160b9ca9d447c971d0de4 Mon Sep 17 00:00:00 2001 From: sameerag Date: Thu, 2 Apr 2020 19:16:01 -0700 Subject: [PATCH 07/11] remove log stmt --- lib/msal-common/src/authority/AuthorityFactory.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/msal-common/src/authority/AuthorityFactory.ts b/lib/msal-common/src/authority/AuthorityFactory.ts index 0094a93809..fa8a5fbfad 100644 --- a/lib/msal-common/src/authority/AuthorityFactory.ts +++ b/lib/msal-common/src/authority/AuthorityFactory.ts @@ -62,7 +62,6 @@ export class AuthorityFactory { } const type = AuthorityFactory.detectAuthorityFromUrl(authorityUrl); - console.log(type.toString()); // Depending on above detection, create the right type. switch (type) { case AuthorityType.Aad: From e93edb0641c40e9981dd234e9f15a047352319ab Mon Sep 17 00:00:00 2001 From: sameerag Date: Thu, 9 Apr 2020 03:59:56 -0700 Subject: [PATCH 08/11] Add unit tests fpr authority changes --- .../src/authority/AuthorityFactory.ts | 36 +++--- lib/msal-common/src/authority/B2cAuthority.ts | 27 ++-- .../src/config/SPAConfiguration.ts | 2 + .../src/error/ClientConfigurationError.ts | 14 +-- .../test/authority/AuthorityFactory.spec.ts | 111 +++++++++++++--- .../test/authority/B2cAuthority.spec.ts | 114 +++++++++++++++++ .../test/config/Configuration.spec.ts | 8 +- .../PublicClientSPAConfiguration.spec.ts | 8 +- lib/msal-common/test/utils/StringConstants.ts | 1 + lib/msal-node/src/network/HttpClient.ts | 9 +- .../test/config/ClientConfiguration.spec.ts | 119 ++++++++++++------ lib/msal-node/test/utils/TestConstants.ts | 16 +-- 12 files changed, 346 insertions(+), 119 deletions(-) create mode 100644 lib/msal-common/test/authority/B2cAuthority.spec.ts diff --git a/lib/msal-common/src/authority/AuthorityFactory.ts b/lib/msal-common/src/authority/AuthorityFactory.ts index fa8a5fbfad..f402739b69 100644 --- a/lib/msal-common/src/authority/AuthorityFactory.ts +++ b/lib/msal-common/src/authority/AuthorityFactory.ts @@ -10,14 +10,19 @@ import { ClientAuthError } from "./../error/ClientAuthError"; import { INetworkModule } from "./../network/INetworkModule"; import { StringUtils } from "./../utils/StringUtils"; import { UrlString } from "./../url/UrlString"; -import { B2cAuthority } from "./B2cAuthority"; - -/** - * Initialize B2CTrustedHostList - */ -export const B2CTrustedHostList = {}; +import { B2cAuthority, B2CTrustedHostList } from "./B2cAuthority"; export class AuthorityFactory { + /** + * Use when Authority is B2C to provide list of trusted/allowed domains. + */ + public static setKnownAuthorities(knownAuthorities: Array): void { + if (!B2CTrustedHostList.length) { + knownAuthorities.forEach(function(authority){ + B2CTrustedHostList.push(authority); + }); + } + } /** * Parse the url and determine the type of authority @@ -30,27 +35,14 @@ export class AuthorityFactory { if (pathSegments[0] === "adfs") { return AuthorityType.Adfs; } - else if (Object.keys(B2CTrustedHostList).length) { + else if (!B2CTrustedHostList.length) { return AuthorityType.B2C; } + // defaults to Aad return AuthorityType.Aad; } - /** - * @hidden - * @ignore - * Use when Authority is B2C is set to True to provide list of allowed domains. - * @param knownAuthorities - */ - public static setKnownAuthorities(knownAuthorities: Array): void { - if (!Object.keys(B2CTrustedHostList).length && knownAuthorities) { - knownAuthorities.forEach(function (authority) { - B2CTrustedHostList[authority] = authority; - }); - } - } - /** * Create an authority object of the correct type based on the url * Performs basic authority validation - checks to see if the authority is of a valid type (eg aad, b2c) @@ -71,7 +63,7 @@ export class AuthorityFactory { // TODO: Support ADFS here in a later PR default: throw ClientAuthError.createInvalidAuthorityTypeError( - `Given Url: ${authorityUrl}` + `${authorityUrl}` ); } } diff --git a/lib/msal-common/src/authority/B2cAuthority.ts b/lib/msal-common/src/authority/B2cAuthority.ts index 71960373f5..cc8fb1ac0f 100644 --- a/lib/msal-common/src/authority/B2cAuthority.ts +++ b/lib/msal-common/src/authority/B2cAuthority.ts @@ -3,45 +3,42 @@ * Licensed under the MIT License. */ import { Authority } from "./Authority"; -import { B2CTrustedHostList } from "./AuthorityFactory"; -import { INetworkModule } from "../network/INetworkModule"; -import { ClientConfigurationError } from "../error/ClientConfigurationError"; import { AuthorityType } from "./AuthorityType"; +import { ClientConfigurationError } from "../error/ClientConfigurationError"; +import { INetworkModule } from "../network/INetworkModule"; + +export const B2CTrustedHostList: string[] = []; /** - * The B2cAuthority class extends the Authority class and adds functionality specific to the Azure AD OAuth Authority. + * The AadAuthority class extends the Authority class and adds functionality specific to the Azure AD OAuth Authority. */ export class B2cAuthority extends Authority { - /** - * Set authority type to B2C - */ + // Set authority type to AAD public get authorityType(): AuthorityType { return AuthorityType.B2C; } + public constructor(authority: string, networkInterface: INetworkModule) { super(authority, networkInterface); } /** - * Returns a promise with the TenantDiscoveryEndpoint + * Returns a promise which resolves to the OIDC endpoint + * Only responds with the endpoint */ public async getOpenIdConfigurationEndpointAsync(): Promise { if (this.isInTrustedHostList(this.canonicalAuthorityUrlComponents.HostNameAndPort)) { return this.defaultOpenIdConfigurationEndpoint; } - throw ClientConfigurationError.createUnsupportedAuthorityValidationError(); + throw ClientConfigurationError.createUntrustedAuthorityError(); } /** * Checks to see if the host is in a list of trusted hosts * @param {string} The host to look up */ - public isInTrustedHostList(host: string): boolean { - if (!Object.keys(B2CTrustedHostList).length) { - throw ClientConfigurationError.createKnownAuthoritiesNotSetError(); - } - - return B2CTrustedHostList[host.toLowerCase()]; + private isInTrustedHostList(host: string): boolean { + return B2CTrustedHostList.includes(host); } } diff --git a/lib/msal-common/src/config/SPAConfiguration.ts b/lib/msal-common/src/config/SPAConfiguration.ts index dececb9ee6..47898a172f 100644 --- a/lib/msal-common/src/config/SPAConfiguration.ts +++ b/lib/msal-common/src/config/SPAConfiguration.ts @@ -15,6 +15,7 @@ import { Configuration, buildConfiguration } from "./Configuration"; export type SPAAuthOptions = { clientId: string; authority?: string; + knownAuthorities?: Array; redirectUri?: string | (() => string); postLogoutRedirectUri?: string | (() => string); }; @@ -32,6 +33,7 @@ export type SPAConfiguration = Configuration & { const DEFAULT_AUTH_OPTIONS: SPAAuthOptions = { clientId: "", authority: null, + knownAuthorities: [], redirectUri: "", postLogoutRedirectUri: "" }; diff --git a/lib/msal-common/src/error/ClientConfigurationError.ts b/lib/msal-common/src/error/ClientConfigurationError.ts index aa2599f3b7..0bd651e5eb 100644 --- a/lib/msal-common/src/error/ClientConfigurationError.ts +++ b/lib/msal-common/src/error/ClientConfigurationError.ts @@ -64,9 +64,9 @@ export const ClientConfigurationErrorMessage = { code: "b2c_known_authorities_not_set", desc: "Must set known authorities when validateAuthority is set to True and using B2C" }, - unsupportedAuthorityValidation: { - code: "unsupported_authority_validation", - desc: "The authority validation is not supported for this authority type." + untrustedAuthority: { + code: "untrusted_authority", + desc: "The provided authority is not a trusted authority. If using B2C, please include this authority in the knownAuthorities config parameter." } }; @@ -207,10 +207,10 @@ export class ClientConfigurationError extends ClientAuthError { } /** - * Throws an error when the user passes an authority not set in knownAuthorities + * Throws error when provided authority is not a member of the trusted host list */ - static createUnsupportedAuthorityValidationError(): ClientConfigurationError { - return new ClientConfigurationError(ClientConfigurationErrorMessage.unsupportedAuthorityValidation.code, - ClientConfigurationErrorMessage.unsupportedAuthorityValidation.desc); + static createUntrustedAuthorityError(): ClientConfigurationError { + return new ClientConfigurationError(ClientConfigurationErrorMessage.untrustedAuthority.code, + ClientConfigurationErrorMessage.untrustedAuthority.desc); } } diff --git a/lib/msal-common/test/authority/AuthorityFactory.spec.ts b/lib/msal-common/test/authority/AuthorityFactory.spec.ts index 302aae0f3b..120512dff4 100644 --- a/lib/msal-common/test/authority/AuthorityFactory.spec.ts +++ b/lib/msal-common/test/authority/AuthorityFactory.spec.ts @@ -1,39 +1,116 @@ import { expect } from "chai"; import { AuthorityFactory } from "../../src/authority/AuthorityFactory"; -import { INetworkModule, NetworkRequestOptions } from "../../src/network/INetworkModule"; -import { ClientConfigurationErrorMessage, ClientAuthErrorMessage, Constants, Authority } from "../../src"; +import { + INetworkModule, + NetworkRequestOptions +} from "../../src/network/INetworkModule"; +import { + ClientConfigurationErrorMessage, + Constants, + Authority, + ClientAuthError, + ClientAuthErrorMessage +} from "../../src"; import { AadAuthority } from "../../src/authority/AadAuthority"; +import { B2cAuthority, B2CTrustedHostList} from "../../src/authority/B2cAuthority"; +import { TEST_CONFIG } from "../utils/StringConstants"; describe("AuthorityFactory.ts Class Unit Tests", () => { - const networkInterface: INetworkModule = { - sendGetRequestAsync(url: string, options?: NetworkRequestOptions): T { + sendGetRequestAsync( + url: string, + options?: NetworkRequestOptions + ): T { return null; }, - sendPostRequestAsync(url: string, options?: NetworkRequestOptions): T { + sendPostRequestAsync( + url: string, + options?: NetworkRequestOptions + ): T { return null; } }; it("AuthorityFactory returns null if given url is null or empty", () => { - expect(() => AuthorityFactory.createInstance("", networkInterface)).to.throw(ClientConfigurationErrorMessage.urlEmptyError.desc); - expect(() => AuthorityFactory.createInstance(null, networkInterface)).to.throw(ClientConfigurationErrorMessage.urlEmptyError.desc); - }); - - it("Throws error for B2C url strings that contain tfp", () => { - expect(() => AuthorityFactory.createInstance("https://contoso.b2clogin.com/tfp/contoso.onmicrosoft.com/B2C_1_signupsignin1", networkInterface)).to.throw(ClientAuthErrorMessage.invalidAuthorityType.desc); + expect(() => + AuthorityFactory.createInstance("", networkInterface) + ).to.throw(ClientConfigurationErrorMessage.urlEmptyError.desc); + expect(() => + AuthorityFactory.createInstance(null, networkInterface) + ).to.throw(ClientConfigurationErrorMessage.urlEmptyError.desc); }); it("Throws error for malformed url strings", () => { - expect(() => AuthorityFactory.createInstance(`http://login.microsoftonline.com/common`, networkInterface)).to.throw(ClientConfigurationErrorMessage.authorityUriInsecure.desc); - expect(() => AuthorityFactory.createInstance(`https://login.microsoftonline.com/`, networkInterface)).to.throw(ClientConfigurationErrorMessage.urlParseError.desc); - expect(() => AuthorityFactory.createInstance("This is not a URI", networkInterface)).to.throw(ClientConfigurationErrorMessage.urlParseError.desc); - expect(() => AuthorityFactory.createInstance("", networkInterface)).to.throw(ClientConfigurationErrorMessage.urlEmptyError.desc); + expect(() => + AuthorityFactory.createInstance( + `http://login.microsoftonline.com/common`, + networkInterface + ) + ).to.throw(ClientConfigurationErrorMessage.authorityUriInsecure.desc); + expect(() => + AuthorityFactory.createInstance( + `https://login.microsoftonline.com/`, + networkInterface + ) + ).to.throw(ClientConfigurationErrorMessage.urlParseError.desc); + expect(() => + AuthorityFactory.createInstance( + "This is not a URI", + networkInterface + ) + ).to.throw(ClientConfigurationErrorMessage.urlParseError.desc); + expect(() => + AuthorityFactory.createInstance("", networkInterface) + ).to.throw(ClientConfigurationErrorMessage.urlEmptyError.desc); }); - it("createInstance returns an AAD instance for any valid url string that does not contain a tfp", () => { - const authorityInstance = AuthorityFactory.createInstance(Constants.DEFAULT_AUTHORITY, networkInterface); + it("createInstance returns an AAD instance if knownAuthorities not provided", () => { + const authorityInstance = AuthorityFactory.createInstance( + Constants.DEFAULT_AUTHORITY, + networkInterface + ); expect(authorityInstance instanceof AadAuthority); expect(authorityInstance instanceof Authority); }); + + it("createInstance returns B2C instance if knownAuthorities is provided", () => { + AuthorityFactory.setKnownAuthorities(["fabrikamb2c.b2clogin.com"]); + const authorityInstance = AuthorityFactory.createInstance( + TEST_CONFIG.b2cValidAuthority, + networkInterface + ); + expect(authorityInstance instanceof B2cAuthority); + expect(authorityInstance instanceof Authority); + }); + + it("Do not add additional authorities to trusted host list if it has already been populated", () => { + AuthorityFactory.setKnownAuthorities(["fabrikamb2c.b2clogin.com"]); + AuthorityFactory.setKnownAuthorities(["fake.b2clogin.com"]); + + console.log(B2CTrustedHostList); + + expect(B2CTrustedHostList).to.include("fabrikamb2c.b2clogin.com"); + expect(B2CTrustedHostList).not.to.include("fake.b2clogin.com"); + expect(B2CTrustedHostList.length).to.equal(1); + }); + + it("Throws error if AuthorityType is not AAD or B2C", done => { + //Right now only way to throw this is to send adfs authority. This will need to change when we implement ADFS + const errorAuthority = "https://login.microsoftonline.com/adfs"; + try { + const authorityInstance = AuthorityFactory.createInstance( + errorAuthority, + networkInterface + ); + } catch (e) { + expect(e).to.be.instanceOf(ClientAuthError); + expect(e.errorCode).to.be.eql( + ClientAuthErrorMessage.invalidAuthorityType.code + ); + expect(e.errorMessage).to.be.eql( + `${ClientAuthErrorMessage.invalidAuthorityType.desc} Given Url: ${errorAuthority}` + ); + done(); + } + }); }); diff --git a/lib/msal-common/test/authority/B2cAuthority.spec.ts b/lib/msal-common/test/authority/B2cAuthority.spec.ts new file mode 100644 index 0000000000..37b7cfac5a --- /dev/null +++ b/lib/msal-common/test/authority/B2cAuthority.spec.ts @@ -0,0 +1,114 @@ +import { expect } from "chai"; +import { B2cAuthority } from "../../src/authority/B2cAuthority"; +import { + INetworkModule, + NetworkRequestOptions +} from "../../src/network/INetworkModule"; +import { Authority } from "../../src/authority/Authority"; +import { AuthorityType } from "../../src/authority/AuthorityType"; +import { TEST_CONFIG } from "../utils/StringConstants"; +import { AuthorityFactory } from "../../src/authority/AuthorityFactory"; +import { + ClientConfigurationError, + ClientConfigurationErrorMessage +} from "../../src"; + +describe("B2cAuthority.ts Class Unit Tests", () => { + describe("Constructor", () => { + let b2cAuthority: B2cAuthority; + beforeEach(() => { + const networkInterface: INetworkModule = { + sendGetRequestAsync( + url: string, + options?: NetworkRequestOptions + ): T { + return null; + }, + sendPostRequestAsync( + url: string, + options?: NetworkRequestOptions + ): T { + return null; + } + }; + AuthorityFactory.setKnownAuthorities(["fabrikamb2c.b2clogin.com"]); + b2cAuthority = new B2cAuthority( + TEST_CONFIG.b2cValidAuthority, + networkInterface + ); + }); + + it("Creates an B2cAuthority that extends the Authority class", () => { + expect(b2cAuthority).to.be.not.null; + expect(b2cAuthority instanceof B2cAuthority).to.be.true; + expect(b2cAuthority instanceof Authority).to.be.true; + }); + + it("Creates an Authority with type B2C", () => { + expect(b2cAuthority.authorityType).to.be.eq(AuthorityType.B2C); + }); + }); + + describe("Public APIs", () => { + it("Returns default OpenID endpoint if the given authority is in the trusted host list", async () => { + const networkInterface: INetworkModule = { + sendGetRequestAsync( + url: string, + options?: NetworkRequestOptions + ): T { + return null; + }, + sendPostRequestAsync( + url: string, + options?: NetworkRequestOptions + ): T { + return null; + } + }; + + AuthorityFactory.setKnownAuthorities(["fabrikamb2c.b2clogin.com"]); + const b2cAuthority = new B2cAuthority( + TEST_CONFIG.b2cValidAuthority, + networkInterface + ); + await expect( + b2cAuthority.getOpenIdConfigurationEndpointAsync() + ).to.eventually.eq( + `${TEST_CONFIG.b2cValidAuthority}/v2.0/.well-known/openid-configuration` + ); + }); + + it("Throws Untrusted Authority Error if the given authority was not passed to knownAuthorities", async () => { + // Can't use sinon here since INetworkModule is an interface, so using variables here instead + const networkInterface: INetworkModule = { + sendGetRequestAsync( + url: string, + options?: NetworkRequestOptions + ): T { + return null; + }, + sendPostRequestAsync( + url: string, + options?: NetworkRequestOptions + ): T { + return null; + } + }; + + const hostUri = + "https://contoso.b2clogin.com/contoso.onmicrosoft.com/b2c_1_susi"; + const b2cAuthority = new B2cAuthority(hostUri, networkInterface); + try { + await b2cAuthority.getOpenIdConfigurationEndpointAsync(); + } catch (e) { + expect(e).to.be.instanceOf(ClientConfigurationError); + expect(e.errorCode).to.be.equal( + ClientConfigurationErrorMessage.untrustedAuthority.code + ); + expect(e.errorMessage).to.be.equal( + ClientConfigurationErrorMessage.untrustedAuthority.desc + ); + } + }); + }); +}); diff --git a/lib/msal-common/test/config/Configuration.spec.ts b/lib/msal-common/test/config/Configuration.spec.ts index 0d38bd55ff..1b8b3e93d5 100644 --- a/lib/msal-common/test/config/Configuration.spec.ts +++ b/lib/msal-common/test/config/Configuration.spec.ts @@ -53,10 +53,10 @@ describe("Configuration.ts Class Unit Tests", () => { await expect(emptyConfig.networkInterface.sendPostRequestAsync("", null)).to.be.rejectedWith("Unexpected error in authentication.: Network interface - sendPostRequestAsync() has not been implemented"); await expect(emptyConfig.networkInterface.sendPostRequestAsync("", null)).to.be.rejectedWith(AuthError); // Logger options checks - expect(emptyConfig.loggerOptions).to.be.not.null; - 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; + // expect(emptyConfig.loggerOptions).to.be.not.null; + // 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; }); const clearFunc = (): void => { diff --git a/lib/msal-common/test/config/PublicClientSPAConfiguration.spec.ts b/lib/msal-common/test/config/PublicClientSPAConfiguration.spec.ts index 5999cd9323..1e7bc988c1 100644 --- a/lib/msal-common/test/config/PublicClientSPAConfiguration.spec.ts +++ b/lib/msal-common/test/config/PublicClientSPAConfiguration.spec.ts @@ -56,10 +56,10 @@ describe("SPAConfiguration.ts Class Unit Tests", () => { await expect(emptyConfig.networkInterface.sendPostRequestAsync("", null)).to.be.rejectedWith("Unexpected error in authentication.: Network interface - sendPostRequestAsync() has not been implemented"); await expect(emptyConfig.networkInterface.sendPostRequestAsync("", null)).to.be.rejectedWith(AuthError); // Logger options checks - expect(emptyConfig.loggerOptions).to.be.not.null; - 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; + // expect(emptyConfig.loggerOptions).to.be.not.null; + // 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; }); const clearFunc = (): void => { diff --git a/lib/msal-common/test/utils/StringConstants.ts b/lib/msal-common/test/utils/StringConstants.ts index 786612263f..738983c0a6 100644 --- a/lib/msal-common/test/utils/StringConstants.ts +++ b/lib/msal-common/test/utils/StringConstants.ts @@ -73,6 +73,7 @@ export const TEST_CONFIG = { MSAL_TENANT_ID: "3338040d-6c67-4c5b-b112-36a304b66dad", validAuthority: TEST_URIS.DEFAULT_INSTANCE + "common", alternateValidAuthority: TEST_URIS.ALTERNATE_INSTANCE + "common", + b2cValidAuthority: "https://fabrikamb2c.b2clogin.com/fabrikamb2c.onmicrosoft.com/b2c_1_susi", applicationName: "msal.js-tests", applicationVersion: "msal.js-tests.1.0.fake", STATE: "1234", diff --git a/lib/msal-node/src/network/HttpClient.ts b/lib/msal-node/src/network/HttpClient.ts index 59d3ee6933..e234318706 100644 --- a/lib/msal-node/src/network/HttpClient.ts +++ b/lib/msal-node/src/network/HttpClient.ts @@ -15,7 +15,6 @@ import axios, { AxiosRequestConfig } from 'axios'; * This class implements the API for network requests. */ export class HttpClient implements INetworkModule { - constructor() { axios.defaults.validateStatus = () => true; } @@ -29,10 +28,10 @@ export class HttpClient implements INetworkModule { url: string, options?: NetworkRequestOptions ): Promise> { - const request: AxiosRequestConfig = { - method: HttpMethod.GET, - url: url, - headers: options && options.headers, + const request: AxiosRequestConfig = { + method: HttpMethod.GET, + url: url, + headers: options && options.headers, }; const response = await axios(request); diff --git a/lib/msal-node/test/config/ClientConfiguration.spec.ts b/lib/msal-node/test/config/ClientConfiguration.spec.ts index 7337dda4ea..3e0f3a81a1 100644 --- a/lib/msal-node/test/config/ClientConfiguration.spec.ts +++ b/lib/msal-node/test/config/ClientConfiguration.spec.ts @@ -1,13 +1,14 @@ -import {buildConfiguration, ClientConfiguration} from "../../src/config/ClientConfiguration"; -import {CACHE} from "../../src/utils/Constants"; -import {HttpClient} from "../../src/network/HttpClient"; -import {TEST_CONSTANTS} from "../utils/TestConstants"; -import {LogLevel, NetworkRequestOptions} from "@azure/msal-common"; +import { + buildConfiguration, + ClientConfiguration, +} from '../../src/config/ClientConfiguration'; +import { CACHE } from '../../src/utils/Constants'; +import { HttpClient } from '../../src/network/HttpClient'; +import { TEST_CONSTANTS } from '../utils/TestConstants'; +import { LogLevel, NetworkRequestOptions } from '@azure/msal-common'; describe('ClientConfiguration tests', () => { - test('builds configuration and assigns default functions', () => { - const config: ClientConfiguration = buildConfiguration({}); // network options @@ -25,22 +26,41 @@ describe('ClientConfiguration tests', () => { expect(config.system.loggerOptions).toBeDefined(); expect(config.system.loggerOptions.piiLoggingEnabled).toBe(false); - config.system.loggerOptions.loggerCallback(LogLevel.Error,"error", false); - config.system.loggerOptions.loggerCallback(LogLevel.Info,"info", false); - config.system.loggerOptions.loggerCallback(LogLevel.Verbose,"verbose", false); - config.system.loggerOptions.loggerCallback(LogLevel.Warning,"warning", false); - config.system.loggerOptions.loggerCallback(LogLevel.Warning,"warning", true); - - expect(console.error).toHaveBeenLastCalledWith("error"); - expect(console.info).toHaveBeenLastCalledWith("info"); - expect(console.debug).toHaveBeenLastCalledWith("verbose"); - expect(console.warn).toHaveBeenLastCalledWith("warning"); + config.system.loggerOptions.loggerCallback( + LogLevel.Error, + 'error', + false + ); + config.system.loggerOptions.loggerCallback( + LogLevel.Info, + 'info', + false + ); + config.system.loggerOptions.loggerCallback( + LogLevel.Verbose, + 'verbose', + false + ); + config.system.loggerOptions.loggerCallback( + LogLevel.Warning, + 'warning', + false + ); + config.system.loggerOptions.loggerCallback( + LogLevel.Warning, + 'warning', + true + ); + + expect(console.error).toHaveBeenLastCalledWith('error'); + expect(console.info).toHaveBeenLastCalledWith('info'); + expect(console.debug).toHaveBeenLastCalledWith('verbose'); + expect(console.warn).toHaveBeenLastCalledWith('warning'); expect(console.warn).toHaveBeenCalledTimes(1); - // auth options - expect(config.auth.authority).toEqual(""); - expect(config.auth.clientId).toEqual(""); + expect(config.auth.authority).toEqual(''); + expect(config.auth.clientId).toEqual(''); // cache options expect(config.cache.cacheLocation).toEqual(CACHE.FILE_CACHE); @@ -48,9 +68,8 @@ describe('ClientConfiguration tests', () => { }); test('builds configuration and assigns default functions', () => { - const testNetworkResult = { - testParam: "testValue" + testParam: 'testValue', }; const config: ClientConfiguration = { @@ -59,41 +78,63 @@ describe('ClientConfiguration tests', () => { authority: TEST_CONSTANTS.AUTHORITY, }, system: { - networkClient : { - sendGetRequestAsync: async (url: string, options?: NetworkRequestOptions): Promise => { - if(url && options) { + networkClient: { + sendGetRequestAsync: async ( + url: string, + options?: NetworkRequestOptions + ): Promise => { + if (url && options) { return testNetworkResult; } }, - sendPostRequestAsync: async (url: string, options?: NetworkRequestOptions): Promise => { - if(url && options) { + sendPostRequestAsync: async ( + url: string, + options?: NetworkRequestOptions + ): Promise => { + if (url && options) { return testNetworkResult; } - } + }, }, loggerOptions: { - loggerCallback: (level: LogLevel, message: string, containsPii: boolean): void => { + loggerCallback: ( + level: LogLevel, + message: string, + containsPii: boolean + ): void => { if (containsPii) { - console.log(`Log level: ${level} Message: ${message}`); + console.log( + `Log level: ${level} Message: ${message}` + ); } }, - piiLoggingEnabled: true - } + piiLoggingEnabled: true, + }, }, cache: { cacheLocation: TEST_CONSTANTS.CACHE_LOCATION, - storeAuthStateInCookie: true - } + storeAuthStateInCookie: true, + }, }; const testNetworkOptions = { headers: new Map(), - body: "" + body: '', }; // network options - expect(config.system.networkClient.sendGetRequestAsync(TEST_CONSTANTS.AUTH_CODE_URL, testNetworkOptions)).resolves.toEqual(testNetworkResult); - expect(config.system.networkClient.sendPostRequestAsync(TEST_CONSTANTS.AUTH_CODE_URL, testNetworkOptions)).resolves.toEqual(testNetworkResult); + expect( + config.system.networkClient.sendGetRequestAsync( + TEST_CONSTANTS.AUTH_CODE_URL, + testNetworkOptions + ) + ).resolves.toEqual(testNetworkResult); + expect( + config.system.networkClient.sendPostRequestAsync( + TEST_CONSTANTS.AUTH_CODE_URL, + testNetworkOptions + ) + ).resolves.toEqual(testNetworkResult); // Logger options checks expect(config.system.loggerOptions).toBeDefined(); @@ -104,7 +145,9 @@ describe('ClientConfiguration tests', () => { expect(config.auth.clientId).toEqual(TEST_CONSTANTS.CLIENT_ID); // cache options - expect(config.cache.cacheLocation).toEqual(TEST_CONSTANTS.CACHE_LOCATION); + expect(config.cache.cacheLocation).toEqual( + TEST_CONSTANTS.CACHE_LOCATION + ); expect(config.cache.storeAuthStateInCookie).toEqual(true); }); }); diff --git a/lib/msal-node/test/utils/TestConstants.ts b/lib/msal-node/test/utils/TestConstants.ts index 8f139e1a04..8879514edc 100644 --- a/lib/msal-node/test/utils/TestConstants.ts +++ b/lib/msal-node/test/utils/TestConstants.ts @@ -3,13 +3,15 @@ */ export const TEST_CONSTANTS = { - CLIENT_ID: "b41a6fbb-c728-4e03-aa59-d25b0fd383b6", - AUTHORITY: "https://login.microsoftonline.com/TenantId", - REDIRECT_URI: "http://localhost:8080", - DEFAULT_GRAPH_SCOPE: ["user.read"], - AUTHORIZATION_CODE: "0.ASgAqPq4kJXMDkamGO53C-4XWVm3ypmrKgtCkdhePY1PBjsoAJg.AQABAAIAAAAm-06blBE1TpVMil8KPQ41DOje1jDj1oK3KxTXGKg89VjLYJi71gx_npOoxVfC7X49MqOX7IltTJOilUId-IAHndHXlfWzoSGq3GUmwAOLMisftceBRtq3YBsvHX7giiuSZXJgpgu03uf3V2h5Z3GJNpnSXT1f7iVFuRvGh1-jqjWxKs2un8AS5rhti1ym1zxkeicKT43va5jQeHVUlTQo69llnwQJ3iKmKLDVq_Q25Au4EQjYaeEx6TP5IZSqPPm7x0bynmjE8cqR5r4ySP4wH8fjnxlLySrUEZObk2VgREB1AdH6-xKIa04EnJEj9dUgTwiFvQumkuHHetFOgH7ep_9diFOdAOQLUK8C9N4Prlj0JiOcgn6l0xYd5Q9691Ylw8UfifLwq_B7f30mMLN64_XgoBY9K9CR1L4EC1kPPwIhVv3m6xmbhXZ3efx-A-bbV2SYcO4D4ZlnQztHzie_GUlredtsdEMAOE3-jaMJs7i2yYMuIEEtRcHIjV_WscVooCDdKmVncHOObWhNUSdULAejBr3pFs0v3QO_xZ269eLu5Z0qHzCZ_EPg2aL-ERz-rpgdclQ_H_KnEtMsC4F1RgAnDjVmSRKJZZdnNLfKSX_Wd40t_nuo4kjN2cSt8QzzeL533zIZ4CxthOsC4HH2RcUZDIgHdLDLT2ukg-Osc6J9URpZP-IUpdjXg_uwbkHEjrXDMBMo2pmCqaWbMJKo5Lr7CrystifnDITXzZmmOah8HV83Xyb6EP8Gno6JRuaG80j8BKDWyb1Yof4rnLI1kZ59n_t2d0LnRBXz50PdWCWX6vtkg-kAV-bGJQr45XDSKBSv0Q_fVsdLMk24NacUZcF5ujUtqv__Bv-wATzCHWlbUDGHC8nHEi84PcYAjSsgAA", - AUTH_CODE_URL: "https://login.microsoftonline.com/TenantId/oauth2.0/v2.0/authorize?client_id=b41a6fbb-c728-4e03-aa59-d25b0fd383b6&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2F8080%2F&response_mode=query&scope=user.read%20openid%20profile%20offline_access", - CACHE_LOCATION: "Test", + CLIENT_ID: 'b41a6fbb-c728-4e03-aa59-d25b0fd383b6', + AUTHORITY: 'https://login.microsoftonline.com/TenantId', + REDIRECT_URI: 'http://localhost:8080', + DEFAULT_GRAPH_SCOPE: ['user.read'], + AUTHORIZATION_CODE: + '0.ASgAqPq4kJXMDkamGO53C-4XWVm3ypmrKgtCkdhePY1PBjsoAJg.AQABAAIAAAAm-06blBE1TpVMil8KPQ41DOje1jDj1oK3KxTXGKg89VjLYJi71gx_npOoxVfC7X49MqOX7IltTJOilUId-IAHndHXlfWzoSGq3GUmwAOLMisftceBRtq3YBsvHX7giiuSZXJgpgu03uf3V2h5Z3GJNpnSXT1f7iVFuRvGh1-jqjWxKs2un8AS5rhti1ym1zxkeicKT43va5jQeHVUlTQo69llnwQJ3iKmKLDVq_Q25Au4EQjYaeEx6TP5IZSqPPm7x0bynmjE8cqR5r4ySP4wH8fjnxlLySrUEZObk2VgREB1AdH6-xKIa04EnJEj9dUgTwiFvQumkuHHetFOgH7ep_9diFOdAOQLUK8C9N4Prlj0JiOcgn6l0xYd5Q9691Ylw8UfifLwq_B7f30mMLN64_XgoBY9K9CR1L4EC1kPPwIhVv3m6xmbhXZ3efx-A-bbV2SYcO4D4ZlnQztHzie_GUlredtsdEMAOE3-jaMJs7i2yYMuIEEtRcHIjV_WscVooCDdKmVncHOObWhNUSdULAejBr3pFs0v3QO_xZ269eLu5Z0qHzCZ_EPg2aL-ERz-rpgdclQ_H_KnEtMsC4F1RgAnDjVmSRKJZZdnNLfKSX_Wd40t_nuo4kjN2cSt8QzzeL533zIZ4CxthOsC4HH2RcUZDIgHdLDLT2ukg-Osc6J9URpZP-IUpdjXg_uwbkHEjrXDMBMo2pmCqaWbMJKo5Lr7CrystifnDITXzZmmOah8HV83Xyb6EP8Gno6JRuaG80j8BKDWyb1Yof4rnLI1kZ59n_t2d0LnRBXz50PdWCWX6vtkg-kAV-bGJQr45XDSKBSv0Q_fVsdLMk24NacUZcF5ujUtqv__Bv-wATzCHWlbUDGHC8nHEi84PcYAjSsgAA', + AUTH_CODE_URL: + 'https://login.microsoftonline.com/TenantId/oauth2.0/v2.0/authorize?client_id=b41a6fbb-c728-4e03-aa59-d25b0fd383b6&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2F8080%2F&response_mode=query&scope=user.read%20openid%20profile%20offline_access', + CACHE_LOCATION: 'Test', }; export const AUTHENTICATION_RESULT = { From 2a23b579ee93b8c6aa0ce34b5978cf89c947fcf3 Mon Sep 17 00:00:00 2001 From: sameerag Date: Thu, 9 Apr 2020 15:15:41 -0700 Subject: [PATCH 09/11] Addressing feedback and fixing tests --- lib/msal-common/package-lock.json | 6 ++++++ lib/msal-common/src/authority/AuthorityFactory.ts | 3 ++- lib/msal-common/src/client/AuthorizationCodeClient.ts | 6 +++--- lib/msal-common/src/config/Configuration.ts | 4 +++- .../test/authority/AuthorityFactory.spec.ts | 10 ++++++++-- lib/msal-common/test/authority/B2cAuthority.spec.ts | 9 ++++++++- .../test/client/AuthorizationCodeClient.spec.ts | 7 ++++++- lib/msal-common/test/client/ClientTestUtils.ts | 1 + lib/msal-node/package-lock.json | 8 ++------ 9 files changed, 39 insertions(+), 15 deletions(-) diff --git a/lib/msal-common/package-lock.json b/lib/msal-common/package-lock.json index 90cfe53ebe..0754cc5957 100644 --- a/lib/msal-common/package-lock.json +++ b/lib/msal-common/package-lock.json @@ -1065,6 +1065,12 @@ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, + "@types/debug": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", + "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", + "dev": true + }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", diff --git a/lib/msal-common/src/authority/AuthorityFactory.ts b/lib/msal-common/src/authority/AuthorityFactory.ts index f402739b69..29620533ca 100644 --- a/lib/msal-common/src/authority/AuthorityFactory.ts +++ b/lib/msal-common/src/authority/AuthorityFactory.ts @@ -35,7 +35,7 @@ export class AuthorityFactory { if (pathSegments[0] === "adfs") { return AuthorityType.Adfs; } - else if (!B2CTrustedHostList.length) { + else if (B2CTrustedHostList.length) { return AuthorityType.B2C; } @@ -54,6 +54,7 @@ export class AuthorityFactory { } const type = AuthorityFactory.detectAuthorityFromUrl(authorityUrl); + // Depending on above detection, create the right type. switch (type) { case AuthorityType.Aad: diff --git a/lib/msal-common/src/client/AuthorizationCodeClient.ts b/lib/msal-common/src/client/AuthorizationCodeClient.ts index f6a8d26829..49810a37e4 100644 --- a/lib/msal-common/src/client/AuthorizationCodeClient.ts +++ b/lib/msal-common/src/client/AuthorizationCodeClient.ts @@ -11,9 +11,9 @@ import { RequestParameterBuilder } from "../server/RequestParameterBuilder"; import { RequestValidator } from "../request/RequestValidator"; import { GrantType } from "../utils/Constants"; import { Configuration } from "../config/Configuration"; -import {ServerAuthorizationTokenResponse} from "../server/ServerAuthorizationTokenResponse"; -import {NetworkResponse} from "../network/NetworkManager"; -import {ScopeSet} from "../request/ScopeSet"; +import { ServerAuthorizationTokenResponse } from "../server/ServerAuthorizationTokenResponse"; +import { NetworkResponse } from "../network/NetworkManager"; +import { ScopeSet } from "../request/ScopeSet"; /** * Oauth2.0 Authorization Code client diff --git a/lib/msal-common/src/config/Configuration.ts b/lib/msal-common/src/config/Configuration.ts index 8679ddaa28..50e6770b81 100644 --- a/lib/msal-common/src/config/Configuration.ts +++ b/lib/msal-common/src/config/Configuration.ts @@ -87,7 +87,9 @@ const DEFAULT_SYSTEM_OPTIONS: SystemOptions = { // Default logger implementation const DEFAULT_LOGGER_IMPLEMENTATION: LoggerOptions = { - loggerCallback: () => {}, + loggerCallback: () => { + // allows users to not pass loggerCallback implementation + }, piiLoggingEnabled: false, logLevel: LogLevel.Info }; diff --git a/lib/msal-common/test/authority/AuthorityFactory.spec.ts b/lib/msal-common/test/authority/AuthorityFactory.spec.ts index 120512dff4..a802756090 100644 --- a/lib/msal-common/test/authority/AuthorityFactory.spec.ts +++ b/lib/msal-common/test/authority/AuthorityFactory.spec.ts @@ -31,6 +31,12 @@ describe("AuthorityFactory.ts Class Unit Tests", () => { } }; + beforeEach(() => { + while (B2CTrustedHostList.length) { + B2CTrustedHostList.pop(); + } + }); + it("AuthorityFactory returns null if given url is null or empty", () => { expect(() => AuthorityFactory.createInstance("", networkInterface) @@ -81,14 +87,14 @@ describe("AuthorityFactory.ts Class Unit Tests", () => { ); expect(authorityInstance instanceof B2cAuthority); expect(authorityInstance instanceof Authority); + + }); it("Do not add additional authorities to trusted host list if it has already been populated", () => { AuthorityFactory.setKnownAuthorities(["fabrikamb2c.b2clogin.com"]); AuthorityFactory.setKnownAuthorities(["fake.b2clogin.com"]); - console.log(B2CTrustedHostList); - expect(B2CTrustedHostList).to.include("fabrikamb2c.b2clogin.com"); expect(B2CTrustedHostList).not.to.include("fake.b2clogin.com"); expect(B2CTrustedHostList.length).to.equal(1); diff --git a/lib/msal-common/test/authority/B2cAuthority.spec.ts b/lib/msal-common/test/authority/B2cAuthority.spec.ts index 37b7cfac5a..a02b7e2cd9 100644 --- a/lib/msal-common/test/authority/B2cAuthority.spec.ts +++ b/lib/msal-common/test/authority/B2cAuthority.spec.ts @@ -1,5 +1,5 @@ import { expect } from "chai"; -import { B2cAuthority } from "../../src/authority/B2cAuthority"; +import { B2cAuthority, B2CTrustedHostList } from "../../src/authority/B2cAuthority"; import { INetworkModule, NetworkRequestOptions @@ -38,6 +38,12 @@ describe("B2cAuthority.ts Class Unit Tests", () => { ); }); + afterEach(() => { + while (B2CTrustedHostList.length) { + B2CTrustedHostList.pop(); + } + }); + it("Creates an B2cAuthority that extends the Authority class", () => { expect(b2cAuthority).to.be.not.null; expect(b2cAuthority instanceof B2cAuthority).to.be.true; @@ -50,6 +56,7 @@ describe("B2cAuthority.ts Class Unit Tests", () => { }); describe("Public APIs", () => { + it("Returns default OpenID endpoint if the given authority is in the trusted host list", async () => { const networkInterface: INetworkModule = { sendGetRequestAsync( diff --git a/lib/msal-common/test/client/AuthorizationCodeClient.spec.ts b/lib/msal-common/test/client/AuthorizationCodeClient.spec.ts index d21b4725c7..dd5d2ffe12 100644 --- a/lib/msal-common/test/client/AuthorizationCodeClient.spec.ts +++ b/lib/msal-common/test/client/AuthorizationCodeClient.spec.ts @@ -19,7 +19,8 @@ import { } from "../utils/StringConstants"; import {BaseClient} from "../../src/client/BaseClient"; import {AADServerParamKeys, PromptValue, ResponseMode, SSOTypes} from "../../src/utils/Constants"; -import {ClientTestUtils} from "./ClientTestUtils"; +import { ClientTestUtils } from "./ClientTestUtils"; +import { B2CTrustedHostList } from "../../src/authority/B2cAuthority"; const expect = chai.expect; chai.use(chaiAsPromised); @@ -33,7 +34,11 @@ describe("AuthorizationCodeClient unit tests", () => { }); afterEach(() => { + config = null; sinon.restore(); + while (B2CTrustedHostList.length) { + B2CTrustedHostList.pop(); + } }); describe("Constructor", () => { diff --git a/lib/msal-common/test/client/ClientTestUtils.ts b/lib/msal-common/test/client/ClientTestUtils.ts index 9c30464e30..c7fdd0f9f3 100644 --- a/lib/msal-common/test/client/ClientTestUtils.ts +++ b/lib/msal-common/test/client/ClientTestUtils.ts @@ -16,6 +16,7 @@ export class ClientTestUtils { authOptions: { clientId: TEST_CONFIG.MSAL_CLIENT_ID, authority: TEST_CONFIG.validAuthority, + knownAuthorities: [] }, storageInterface: { setItem(key: string, value: string): void { diff --git a/lib/msal-node/package-lock.json b/lib/msal-node/package-lock.json index 52c999a70f..93936b1515 100644 --- a/lib/msal-node/package-lock.json +++ b/lib/msal-node/package-lock.json @@ -1,6 +1,6 @@ { "name": "@azure/msal-node", - "version": "0.0.1", + "version": "0.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2124,7 +2124,6 @@ "version": "0.19.2", "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", - "dev": true, "requires": { "follow-redirects": "1.5.10" } @@ -4262,7 +4261,6 @@ "version": "1.5.10", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "dev": true, "requires": { "debug": "=3.1.0" }, @@ -4271,7 +4269,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -4279,8 +4276,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, From fb4c5cfd872fcf5167d6108b15231e612b232961 Mon Sep 17 00:00:00 2001 From: sameerag Date: Thu, 9 Apr 2020 15:39:00 -0700 Subject: [PATCH 10/11] Initiate knownAuthorities in msal-node --- lib/msal-node/src/config/ClientConfiguration.ts | 1 + samples/msal-node-auth-code/index.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/msal-node/src/config/ClientConfiguration.ts b/lib/msal-node/src/config/ClientConfiguration.ts index 6d01206cf0..0a859cf5a9 100644 --- a/lib/msal-node/src/config/ClientConfiguration.ts +++ b/lib/msal-node/src/config/ClientConfiguration.ts @@ -53,6 +53,7 @@ export type ClientConfiguration = { const DEFAULT_AUTH_OPTIONS: NodeAuthOptions = { clientId: '', authority: '', + knownAuthorities: [], }; const DEFAULT_CACHE_OPTIONS: CacheOptions = { diff --git a/samples/msal-node-auth-code/index.js b/samples/msal-node-auth-code/index.js index 24fc47057b..f89255251b 100644 --- a/samples/msal-node-auth-code/index.js +++ b/samples/msal-node-auth-code/index.js @@ -41,7 +41,10 @@ function redirectToAzureAd(req, res){ console.log(response); res.redirect(response); }) - .catch((error) => console.log(JSON.stringify(error))); + .catch((error) => { + console.log(error); + console.log(JSON.stringify(error)) + }); } function acquireToken(req, res){ From 67311ff9b13d4ba46ea326b754c8d6da8484456e Mon Sep 17 00:00:00 2001 From: sameerag Date: Sun, 12 Apr 2020 13:29:52 -0700 Subject: [PATCH 11/11] Add client_info for tokenResponse --- lib/msal-common/src/client/AuthorizationCodeClient.ts | 1 + lib/msal-common/src/server/RequestParameterBuilder.ts | 11 +++++++++-- lib/msal-common/src/utils/Constants.ts | 2 ++ samples/msal-node-auth-code/index.js | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/msal-common/src/client/AuthorizationCodeClient.ts b/lib/msal-common/src/client/AuthorizationCodeClient.ts index 49810a37e4..6a0e1db42c 100644 --- a/lib/msal-common/src/client/AuthorizationCodeClient.ts +++ b/lib/msal-common/src/client/AuthorizationCodeClient.ts @@ -95,6 +95,7 @@ export class AuthorizationCodeClient extends BaseClient { } parameterBuilder.addGrantType(GrantType.AUTHORIZATION_CODE_GRANT); + parameterBuilder.addClientInfo(); return parameterBuilder.createQueryString(); } diff --git a/lib/msal-common/src/server/RequestParameterBuilder.ts b/lib/msal-common/src/server/RequestParameterBuilder.ts index e4430ad740..63da48726c 100644 --- a/lib/msal-common/src/server/RequestParameterBuilder.ts +++ b/lib/msal-common/src/server/RequestParameterBuilder.ts @@ -3,8 +3,7 @@ * Licensed under the MIT License. */ -import { AADServerParamKeys, SSOTypes } from "../utils/Constants"; -import { Constants } from "../utils/Constants"; +import { AADServerParamKeys, SSOTypes, Constants, ClientInfo} from "../utils/Constants"; import { ScopeSet } from "../request/ScopeSet"; import { ClientConfigurationError } from "../error/ClientConfigurationError"; @@ -179,6 +178,14 @@ export class RequestParameterBuilder { this.parameters.set(AADServerParamKeys.GRANT_TYPE, encodeURIComponent(grantType)); } + /** + * add client info + * + */ + addClientInfo(): void { + this.parameters.set(ClientInfo, "1"); + } + /** * Utility to create a URL from the params map */ diff --git a/lib/msal-common/src/utils/Constants.ts b/lib/msal-common/src/utils/Constants.ts index 7ba40b3818..0cf3bf4317 100644 --- a/lib/msal-common/src/utils/Constants.ts +++ b/lib/msal-common/src/utils/Constants.ts @@ -215,3 +215,5 @@ export enum GrantType { REFRESH_TOKEN_GRANT = "refresh_token", DEVICE_CODE_GRANT = "device_code" }; + +export const ClientInfo = "client_info"; diff --git a/samples/msal-node-auth-code/index.js b/samples/msal-node-auth-code/index.js index f89255251b..c81fa16e25 100644 --- a/samples/msal-node-auth-code/index.js +++ b/samples/msal-node-auth-code/index.js @@ -56,7 +56,7 @@ function acquireToken(req, res){ }; pca.acquireTokenByCode(tokenRequest).then((response) => { - console.log(JSON.stringify(response)); + console.log(response); res.send(200); }).catch((error) => { res.send(500);