diff --git a/sdk/identity/identity-cache-persistence/test/internal/node/clientCertificateCredential.spec.ts b/sdk/identity/identity-cache-persistence/test/internal/node/clientCertificateCredential.spec.ts index 5ab4bba06d8a..7cd190521a32 100644 --- a/sdk/identity/identity-cache-persistence/test/internal/node/clientCertificateCredential.spec.ts +++ b/sdk/identity/identity-cache-persistence/test/internal/node/clientCertificateCredential.spec.ts @@ -15,7 +15,7 @@ import { TokenCachePersistenceOptions } from "../../../../identity/src"; import { MsalTestCleanup, msalNodeTestSetup } from "../../../../identity/test/msalTestUtils"; -import { MsalNode } from "../../../../identity/src/msal/nodeFlows/nodeCommon"; +import { MsalNode } from "../../../../identity/src/msal/nodeFlows/msalNodeCommon"; import { createPersistence } from "./setup.spec"; diff --git a/sdk/identity/identity-cache-persistence/test/internal/node/clientSecretCredential.spec.ts b/sdk/identity/identity-cache-persistence/test/internal/node/clientSecretCredential.spec.ts index 7b2de57ae0bb..d0e65cc9946e 100644 --- a/sdk/identity/identity-cache-persistence/test/internal/node/clientSecretCredential.spec.ts +++ b/sdk/identity/identity-cache-persistence/test/internal/node/clientSecretCredential.spec.ts @@ -11,7 +11,7 @@ import { ConfidentialClientApplication } from "@azure/msal-node"; import { ClientSecretCredential, TokenCachePersistenceOptions } from "../../../../identity/src"; import { MsalTestCleanup, msalNodeTestSetup } from "../../../../identity/test/msalTestUtils"; -import { MsalNode } from "../../../../identity/src/msal/nodeFlows/nodeCommon"; +import { MsalNode } from "../../../../identity/src/msal/nodeFlows/msalNodeCommon"; import { createPersistence } from "./setup.spec"; diff --git a/sdk/identity/identity-cache-persistence/test/internal/node/deviceCodeCredential.spec.ts b/sdk/identity/identity-cache-persistence/test/internal/node/deviceCodeCredential.spec.ts index 280ab8dc113a..073ddabb9723 100644 --- a/sdk/identity/identity-cache-persistence/test/internal/node/deviceCodeCredential.spec.ts +++ b/sdk/identity/identity-cache-persistence/test/internal/node/deviceCodeCredential.spec.ts @@ -11,7 +11,7 @@ import { isLiveMode } from "@azure-tools/test-recorder"; import { DeviceCodeCredential, TokenCachePersistenceOptions } from "../../../../identity/src"; import { MsalTestCleanup, msalNodeTestSetup } from "../../../../identity/test/msalTestUtils"; -import { MsalNode } from "../../../../identity/src/msal/nodeFlows/nodeCommon"; +import { MsalNode } from "../../../../identity/src/msal/nodeFlows/msalNodeCommon"; import { createPersistence } from "./setup.spec"; diff --git a/sdk/identity/identity-cache-persistence/test/internal/node/usernamePasswordCredential.spec.ts b/sdk/identity/identity-cache-persistence/test/internal/node/usernamePasswordCredential.spec.ts index 390a8f298aaf..48cdcce246d6 100644 --- a/sdk/identity/identity-cache-persistence/test/internal/node/usernamePasswordCredential.spec.ts +++ b/sdk/identity/identity-cache-persistence/test/internal/node/usernamePasswordCredential.spec.ts @@ -11,7 +11,7 @@ import { PublicClientApplication } from "@azure/msal-node"; import { UsernamePasswordCredential, TokenCachePersistenceOptions } from "../../../../identity/src"; import { MsalTestCleanup, msalNodeTestSetup } from "../../../../identity/test/msalTestUtils"; -import { MsalNode } from "../../../../identity/src/msal/nodeFlows/nodeCommon"; +import { MsalNode } from "../../../../identity/src/msal/nodeFlows/msalNodeCommon"; import { createPersistence } from "./setup.spec"; diff --git a/sdk/identity/identity/src/client/identityClient.ts b/sdk/identity/identity/src/client/identityClient.ts index f30c9314da90..b4e84501d1be 100644 --- a/sdk/identity/identity/src/client/identityClient.ts +++ b/sdk/identity/identity/src/client/identityClient.ts @@ -2,9 +2,9 @@ // Licensed under the MIT license. import { INetworkModule, NetworkRequestOptions, NetworkResponse } from "@azure/msal-common"; -import { CommonClientOptions, ServiceClient } from "@azure/core-client"; import { AccessToken, GetTokenOptions } from "@azure/core-auth"; import { SpanStatusCode } from "@azure/core-tracing"; +import { ServiceClient } from "@azure/core-client"; import { isNode } from "@azure/core-util"; import { createHttpHeaders, @@ -17,6 +17,7 @@ import { getIdentityTokenEndpointSuffix } from "../util/identityTokenEndpoint"; import { DefaultAuthorityHost } from "../constants"; import { createSpan } from "../util/tracing"; import { logger } from "../util/logging"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; const noCorrelationId = "noCorrelationId"; @@ -36,6 +37,19 @@ export interface TokenResponse { refreshToken?: string; } +/** + * Internal type roughly matching the raw responses of the authentication endpoints. + * + * @internal + */ +export interface TokenResponseParsedBody { + token?: string; + access_token?: string; + refresh_token?: string; + expires_in: number; + expires_on?: number | string; +} + /** * @internal */ @@ -89,23 +103,19 @@ export class IdentityClient extends ServiceClient implements INetworkModule { async sendTokenRequest( request: PipelineRequest, - expiresOnParser?: (responseBody: any) => number + expiresOnParser?: (responseBody: TokenResponseParsedBody) => number ): Promise { logger.info(`IdentityClient: sending token request to [${request.url}]`); const response = await this.sendRequest(request); expiresOnParser = expiresOnParser || - ((responseBody: any) => { + ((responseBody: TokenResponseParsedBody) => { return Date.now() + responseBody.expires_in * 1000; }); if (response.bodyAsText && (response.status === 200 || response.status === 201)) { - const parsedBody: { - token?: string; - access_token?: string; - refresh_token?: string; - } = JSON.parse(response.bodyAsText); + const parsedBody: TokenResponseParsedBody = JSON.parse(response.bodyAsText); if (!parsedBody.access_token) { return null; @@ -138,7 +148,7 @@ export class IdentityClient extends ServiceClient implements INetworkModule { scopes: string, refreshToken: string | undefined, clientSecret: string | undefined, - expiresOnParser?: (responseBody: any) => number, + expiresOnParser?: (responseBody: TokenResponseParsedBody) => number, options?: GetTokenOptions ): Promise { if (refreshToken === undefined) { @@ -295,16 +305,3 @@ export class IdentityClient extends ServiceClient implements INetworkModule { }; } } - -/** - * Provides options to configure how the Identity library makes authentication - * requests to Azure Active Directory. - */ -export interface TokenCredentialOptions extends CommonClientOptions { - /** - * The authority host to use for authentication requests. - * Possible values are available through {@link AzureAuthorityHosts}. - * The default is "https://login.microsoftonline.com". - */ - authorityHost?: string; -} diff --git a/sdk/identity/identity/src/credentials/authorizationCodeCredential.browser.ts b/sdk/identity/identity/src/credentials/authorizationCodeCredential.browser.ts index ceb2c40eb988..18ae0ed04d41 100644 --- a/sdk/identity/identity/src/credentials/authorizationCodeCredential.browser.ts +++ b/sdk/identity/identity/src/credentials/authorizationCodeCredential.browser.ts @@ -3,7 +3,7 @@ import { TokenCredential, AccessToken } from "@azure/core-auth"; -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { credentialLogger, formatError } from "../util/logging"; const BrowserNotSupportedError = new Error( diff --git a/sdk/identity/identity/src/credentials/authorizationCodeCredential.ts b/sdk/identity/identity/src/credentials/authorizationCodeCredential.ts index f87c72b3924d..f45a082963a8 100644 --- a/sdk/identity/identity/src/credentials/authorizationCodeCredential.ts +++ b/sdk/identity/identity/src/credentials/authorizationCodeCredential.ts @@ -2,7 +2,7 @@ // Licensed under the MIT license. import { TokenCredential, GetTokenOptions, AccessToken } from "@azure/core-auth"; -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { credentialLogger } from "../util/logging"; import { checkTenantId } from "../util/checkTenantId"; import { MsalAuthorizationCode } from "../msal/nodeFlows/msalAuthorizationCode"; @@ -101,7 +101,7 @@ export class AuthorizationCodeCredential implements TokenCredential { // the clientId+clientSecret constructor this.authorizationCode = authorizationCodeOrRedirectUri; this.redirectUri = redirectUriOrOptions; - // options okay + // in this case, options are good as they come } else { // clientId only this.authorizationCode = clientSecretOrAuthorizationCode; diff --git a/sdk/identity/identity/src/credentials/azureApplicationCredential.browser.ts b/sdk/identity/identity/src/credentials/azureApplicationCredential.browser.ts index a2c85b71f9be..0d26acc3a200 100644 --- a/sdk/identity/identity/src/credentials/azureApplicationCredential.browser.ts +++ b/sdk/identity/identity/src/credentials/azureApplicationCredential.browser.ts @@ -3,7 +3,7 @@ import { AccessToken } from "@azure/core-auth"; -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { credentialLogger, formatError } from "../util/logging"; import { ChainedTokenCredential } from "./chainedTokenCredential"; diff --git a/sdk/identity/identity/src/credentials/azureApplicationCredential.ts b/sdk/identity/identity/src/credentials/azureApplicationCredential.ts index 0fe2682104a4..9d48fd9298ff 100644 --- a/sdk/identity/identity/src/credentials/azureApplicationCredential.ts +++ b/sdk/identity/identity/src/credentials/azureApplicationCredential.ts @@ -5,7 +5,7 @@ // Licensed under the MIT license. import { TokenCredential } from "@azure/core-auth"; -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { ChainedTokenCredential } from "./chainedTokenCredential"; import { EnvironmentCredential } from "./environmentCredential"; import { CredentialPersistenceOptions } from "./credentialPersistenceOptions"; @@ -46,8 +46,7 @@ export class AzureApplicationCredential extends ChainedTokenCredential { * Creates an instance of the AzureApplicationCredential class. * * The AzureApplicationCredential provides a default {@link ChainedTokenCredential} configuration that should - * work for most applications that use the Azure SDK. The following credential - * types will be tried, in order: + * work for most applications deployed on Azure. The following credential types will be tried, in order: * * - {@link EnvironmentCredential} * - {@link ManagedIdentityCredential} diff --git a/sdk/identity/identity/src/credentials/azureCliCredential.ts b/sdk/identity/identity/src/credentials/azureCliCredential.ts index cff752150ec5..21dcd9a5c805 100644 --- a/sdk/identity/identity/src/credentials/azureCliCredential.ts +++ b/sdk/identity/identity/src/credentials/azureCliCredential.ts @@ -117,7 +117,7 @@ export class AzureCliCredential implements TokenCredential { let responseData = ""; - const { span } = createSpan("AzureCliCredential.getToken", options); + const { span } = createSpan(`${this.constructor.name}.getToken`, options); try { const obj = await cliCredentialInternals.getAzureCliAccessToken(resource, tenantId); diff --git a/sdk/identity/identity/src/credentials/azureCliCredentialOptions.ts b/sdk/identity/identity/src/credentials/azureCliCredentialOptions.ts index b50807eab973..635104d08f54 100644 --- a/sdk/identity/identity/src/credentials/azureCliCredentialOptions.ts +++ b/sdk/identity/identity/src/credentials/azureCliCredentialOptions.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; /** * Options for the {@link AzureCliCredential} diff --git a/sdk/identity/identity/src/credentials/azurePowerShellCredentialOptions.ts b/sdk/identity/identity/src/credentials/azurePowerShellCredentialOptions.ts index aa48462dbd10..0d6011a66810 100644 --- a/sdk/identity/identity/src/credentials/azurePowerShellCredentialOptions.ts +++ b/sdk/identity/identity/src/credentials/azurePowerShellCredentialOptions.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; /** * Options for the {@link AzurePowerShellCredential} diff --git a/sdk/identity/identity/src/credentials/clientCertificateCredentialOptions.ts b/sdk/identity/identity/src/credentials/clientCertificateCredentialOptions.ts index b4d53a2ecadf..6a9b56e1d428 100644 --- a/sdk/identity/identity/src/credentials/clientCertificateCredentialOptions.ts +++ b/sdk/identity/identity/src/credentials/clientCertificateCredentialOptions.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { CredentialPersistenceOptions } from "./credentialPersistenceOptions"; /** diff --git a/sdk/identity/identity/src/credentials/clientSecretCredential.browser.ts b/sdk/identity/identity/src/credentials/clientSecretCredential.browser.ts index f7fe26741556..3a52de38126e 100644 --- a/sdk/identity/identity/src/credentials/clientSecretCredential.browser.ts +++ b/sdk/identity/identity/src/credentials/clientSecretCredential.browser.ts @@ -6,7 +6,8 @@ import { createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipel import { SpanStatusCode } from "@azure/core-tracing"; import { credentialLogger, formatError, formatSuccess } from "../util/logging"; import { getIdentityTokenEndpointSuffix } from "../util/identityTokenEndpoint"; -import { TokenCredentialOptions, IdentityClient } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; +import { IdentityClient } from "../client/identityClient"; import { createSpan } from "../util/tracing"; const logger = credentialLogger("ClientSecretCredential"); @@ -66,7 +67,7 @@ export class ClientSecretCredential implements TokenCredential { options?: GetTokenOptions ): Promise { const { span, updatedOptions: newOptions } = createSpan( - "ClientSecretCredential.getToken", + `${this.constructor.name}.getToken`, options ); diff --git a/sdk/identity/identity/src/credentials/clientSecretCredentialOptions.ts b/sdk/identity/identity/src/credentials/clientSecretCredentialOptions.ts index 5637affc2e66..f5b83b05437e 100644 --- a/sdk/identity/identity/src/credentials/clientSecretCredentialOptions.ts +++ b/sdk/identity/identity/src/credentials/clientSecretCredentialOptions.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { CredentialPersistenceOptions } from "./credentialPersistenceOptions"; /** diff --git a/sdk/identity/identity/src/credentials/credentialPersistenceOptions.ts b/sdk/identity/identity/src/credentials/credentialPersistenceOptions.ts index 87ac0424b268..4aa21c5c3b73 100644 --- a/sdk/identity/identity/src/credentials/credentialPersistenceOptions.ts +++ b/sdk/identity/identity/src/credentials/credentialPersistenceOptions.ts @@ -32,7 +32,7 @@ export interface CredentialPersistenceOptions { * } * * main().catch((error) => { - * console.error("An error occured:", error); + * console.error("An error occurred:", error); * process.exit(1); * }); * ``` diff --git a/sdk/identity/identity/src/credentials/defaultAzureCredential.browser.ts b/sdk/identity/identity/src/credentials/defaultAzureCredential.browser.ts index 2f622a38e319..8b8340bd1e72 100644 --- a/sdk/identity/identity/src/credentials/defaultAzureCredential.browser.ts +++ b/sdk/identity/identity/src/credentials/defaultAzureCredential.browser.ts @@ -3,7 +3,7 @@ import { AccessToken } from "@azure/core-auth"; -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { credentialLogger, formatError } from "../util/logging"; import { ChainedTokenCredential } from "./chainedTokenCredential"; diff --git a/sdk/identity/identity/src/credentials/defaultAzureCredential.ts b/sdk/identity/identity/src/credentials/defaultAzureCredential.ts index 76550f794253..6d57ff15925f 100644 --- a/sdk/identity/identity/src/credentials/defaultAzureCredential.ts +++ b/sdk/identity/identity/src/credentials/defaultAzureCredential.ts @@ -3,7 +3,7 @@ import { TokenCredential } from "@azure/core-auth"; -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { ChainedTokenCredential } from "./chainedTokenCredential"; diff --git a/sdk/identity/identity/src/credentials/environmentCredential.ts b/sdk/identity/identity/src/credentials/environmentCredential.ts index 1545a42557f8..011116641862 100644 --- a/sdk/identity/identity/src/credentials/environmentCredential.ts +++ b/sdk/identity/identity/src/credentials/environmentCredential.ts @@ -4,7 +4,7 @@ import { AccessToken, TokenCredential, GetTokenOptions } from "@azure/core-auth"; import { credentialLogger, processEnvVars, formatSuccess, formatError } from "../util/logging"; -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { ClientSecretCredential } from "./clientSecretCredential"; import { AuthenticationError, CredentialUnavailableError } from "../errors"; import { checkTenantId } from "../util/checkTenantId"; @@ -28,7 +28,8 @@ export const AllSupportedEnvironmentVariables = [ "AZURE_PASSWORD" ]; -const logger = credentialLogger("EnvironmentCredential"); +const credentialName = "EnvironmentCredential"; +const logger = credentialLogger(credentialName); /** * Enables authentication to Azure Active Directory depending on the available environment variables. @@ -124,7 +125,7 @@ export class EnvironmentCredential implements TokenCredential { * @param options - Optional parameters. See {@link GetTokenOptions}. */ async getToken(scopes: string | string[], options: GetTokenOptions = {}): Promise { - return trace("EnvironmentCredential.getToken", options, async (newOptions) => { + return trace(`${credentialName}.getToken`, options, async (newOptions) => { if (this._credential) { try { const result = await this._credential.getToken(scopes, newOptions); @@ -132,8 +133,7 @@ export class EnvironmentCredential implements TokenCredential { return result; } catch (err) { const authenticationError = new AuthenticationError(400, { - error: - "EnvironmentCredential authentication failed. To troubleshoot, visit https://aka.ms/azsdk/js/identity/environmentcredential/troubleshoot.", + error: `${credentialName} authentication failed. To troubleshoot, visit https://aka.ms/azsdk/js/identity/environmentcredential/troubleshoot.`, error_description: err.message .toString() .split("More details:") @@ -144,7 +144,7 @@ export class EnvironmentCredential implements TokenCredential { } } throw new CredentialUnavailableError( - "EnvironmentCredential is unavailable. No underlying credential could be used. To troubleshoot, visit https://aka.ms/azsdk/js/identity/environmentcredential/troubleshoot." + `${credentialName} is unavailable. No underlying credential could be used. To troubleshoot, visit https://aka.ms/azsdk/js/identity/environmentcredential/troubleshoot.` ); }); } diff --git a/sdk/identity/identity/src/credentials/interactiveBrowserCredential.browser.ts b/sdk/identity/identity/src/credentials/interactiveBrowserCredential.browser.ts index bbc4a735fba0..a7c302200dba 100644 --- a/sdk/identity/identity/src/credentials/interactiveBrowserCredential.browser.ts +++ b/sdk/identity/identity/src/credentials/interactiveBrowserCredential.browser.ts @@ -8,7 +8,7 @@ import { trace } from "../util/tracing"; import { MsalFlow } from "../msal/flows"; import { AuthenticationRecord } from "../msal/types"; import { MSALAuthCode } from "../msal/browserFlows/msalAuthCode"; -import { MsalBrowserFlowOptions } from "../msal/browserFlows/browserCommon"; +import { MsalBrowserFlowOptions } from "../msal/browserFlows/msalBrowserCommon"; import { InteractiveBrowserCredentialInBrowserOptions, InteractiveBrowserCredentialNodeOptions diff --git a/sdk/identity/identity/src/credentials/interactiveCredentialOptions.ts b/sdk/identity/identity/src/credentials/interactiveCredentialOptions.ts index 4fe098c14daf..a3b061a6d823 100644 --- a/sdk/identity/identity/src/credentials/interactiveCredentialOptions.ts +++ b/sdk/identity/identity/src/credentials/interactiveCredentialOptions.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { AuthenticationRecord } from "../msal/types"; /** diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/appServiceMsi2017.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/appServiceMsi2017.ts index 520f1fd05c62..229178e11316 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/appServiceMsi2017.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/appServiceMsi2017.ts @@ -1,21 +1,31 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { createHttpHeaders, PipelineRequestOptions } from "@azure/core-rest-pipeline"; +import { + createHttpHeaders, + createPipelineRequest, + PipelineRequestOptions +} from "@azure/core-rest-pipeline"; import { AccessToken, GetTokenOptions } from "@azure/core-auth"; +import { TokenResponseParsedBody } from "../../client/identityClient"; import { credentialLogger } from "../../util/logging"; import { MSI, MSIConfiguration } from "./models"; -import { mapScopesToResource, msiGenericGetToken } from "./utils"; +import { mapScopesToResource } from "./utils"; const msiName = "ManagedIdentityCredential - AppServiceMSI 2017"; const logger = credentialLogger(msiName); -function expiresInParser(requestBody: any): number { - // Parse a date format like "06/20/2019 02:57:58 +00:00" and - // convert it into a JavaScript-formatted date - return Date.parse(requestBody.expires_on); +/** + * Formats the expiration date of the received token into the number of milliseconds between that date and midnight, January 1, 1970. + */ +function expiresOnParser(requestBody: TokenResponseParsedBody): number { + // App Service always returns string expires_on values. + return Date.parse(requestBody.expires_on! as string); } +/** + * Generates the options used on the request for an access token. + */ function prepareRequestOptions( scopes: string | string[], clientId?: string @@ -25,7 +35,7 @@ function prepareRequestOptions( throw new Error(`${msiName}: Multiple scopes are not supported.`); } - const queryParameters: any = { + const queryParameters: Record = { resource, "api-version": "2017-09-01" }; @@ -54,6 +64,9 @@ function prepareRequestOptions( }; } +/** + * Defines how to determine whether the Azure App Service MSI is available, and also how to retrieve a token from the Azure App Service MSI. + */ export const appServiceMsi2017: MSI = { async isAvailable(scopes): Promise { const resource = mapScopesToResource(scopes); @@ -80,11 +93,13 @@ export const appServiceMsi2017: MSI = { `${msiName}: Using the endpoint and the secret coming form the environment variables: MSI_ENDPOINT=${process.env.MSI_ENDPOINT} and MSI_SECRET=[REDACTED].` ); - return msiGenericGetToken( - identityClient, - prepareRequestOptions(scopes, clientId), - expiresInParser, - getTokenOptions - ); + const request = createPipelineRequest({ + abortSignal: getTokenOptions.abortSignal, + ...prepareRequestOptions(scopes, clientId), + // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS). + allowInsecureConnection: true + }); + const tokenResponse = await identityClient.sendTokenRequest(request, expiresOnParser); + return (tokenResponse && tokenResponse.accessToken) || null; } }; diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/arcMsi.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/arcMsi.ts index 8523e6938fe2..b358792814bb 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/arcMsi.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/arcMsi.ts @@ -8,25 +8,25 @@ import { } from "@azure/core-rest-pipeline"; import { AccessToken, GetTokenOptions } from "@azure/core-auth"; import { readFile } from "fs"; -import { MSI, MSIConfiguration } from "./models"; +import { AuthenticationError } from "../../errors"; import { credentialLogger } from "../../util/logging"; import { IdentityClient } from "../../client/identityClient"; -import { mapScopesToResource, msiGenericGetToken } from "./utils"; +import { mapScopesToResource } from "./utils"; +import { MSI, MSIConfiguration } from "./models"; import { azureArcAPIVersion } from "./constants"; -import { AuthenticationError } from "../../errors"; const msiName = "ManagedIdentityCredential - Azure Arc MSI"; const logger = credentialLogger(msiName); -// Azure Arc MSI doesn't have a special expiresIn parser. -const expiresInParser = undefined; - +/** + * Generates the options used on the request for an access token. + */ function prepareRequestOptions(scopes: string | string[]): PipelineRequestOptions { const resource = mapScopesToResource(scopes); if (!resource) { throw new Error(`${msiName}: Multiple scopes are not supported.`); } - const queryParameters: any = { + const queryParameters: Record = { resource, "api-version": azureArcAPIVersion }; @@ -49,7 +49,10 @@ function prepareRequestOptions(scopes: string | string[]): PipelineRequestOption }); } -// Since "fs"'s readFileSync locks the thread, and to avoid extra dependencies. +/** + * Retrieves the file contents at the given path using promises. + * Useful since `fs`'s readFileSync locks the thread, and to avoid extra dependencies. + */ function readFileAsync(path: string, options: { encoding: string }): Promise { return new Promise((resolve, reject) => readFile(path, options, (err, data) => { @@ -61,6 +64,9 @@ function readFileAsync(path: string, options: { encoding: string }): Promise { const resource = mapScopesToResource(scopes); @@ -132,6 +141,12 @@ export const arcMsi: MSI = { const key = await readFileAsync(filePath, { encoding: "utf-8" }); requestOptions.headers?.set("Authorization", `Basic ${key}`); - return msiGenericGetToken(identityClient, requestOptions, expiresInParser, getTokenOptions); + const request = createPipelineRequest({ + ...requestOptions, + // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS). + allowInsecureConnection: true + }); + const tokenResponse = await identityClient.sendTokenRequest(request); + return (tokenResponse && tokenResponse.accessToken) || null; } }; diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/cloudShellMsi.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/cloudShellMsi.ts index be3e20ebf77d..8ff17b06808e 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/cloudShellMsi.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/cloudShellMsi.ts @@ -1,18 +1,22 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { createHttpHeaders, PipelineRequestOptions } from "@azure/core-rest-pipeline"; +import { + createHttpHeaders, + createPipelineRequest, + PipelineRequestOptions +} from "@azure/core-rest-pipeline"; +import { credentialLogger } from "../../util/logging"; import { AccessToken, GetTokenOptions } from "@azure/core-auth"; import { MSI, MSIConfiguration } from "./models"; -import { credentialLogger } from "../../util/logging"; -import { mapScopesToResource, msiGenericGetToken } from "./utils"; +import { mapScopesToResource } from "./utils"; const msiName = "ManagedIdentityCredential - CloudShellMSI"; const logger = credentialLogger(msiName); -// Cloud Shell MSI doesn't have a special expiresIn parser. -const expiresInParser = undefined; - +/** + * Generates the options used on the request for an access token. + */ function prepareRequestOptions( scopes: string | string[], clientId?: string @@ -22,7 +26,7 @@ function prepareRequestOptions( throw new Error(`${msiName}: Multiple scopes are not supported.`); } - const body: any = { + const body: Record = { resource }; @@ -47,6 +51,9 @@ function prepareRequestOptions( }; } +/** + * Defines how to determine whether the Azure Cloud Shell MSI is available, and also how to retrieve a token from the Azure Cloud Shell MSI. + */ export const cloudShellMsi: MSI = { async isAvailable(scopes): Promise { const resource = mapScopesToResource(scopes); @@ -70,11 +77,13 @@ export const cloudShellMsi: MSI = { `${msiName}: Using the endpoint coming form the environment variable MSI_ENDPOINT = ${process.env.MSI_ENDPOINT}.` ); - return msiGenericGetToken( - identityClient, - prepareRequestOptions(scopes, clientId), - expiresInParser, - getTokenOptions - ); + const request = createPipelineRequest({ + abortSignal: getTokenOptions.abortSignal, + ...prepareRequestOptions(scopes, clientId), + // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS). + allowInsecureConnection: true + }); + const tokenResponse = await identityClient.sendTokenRequest(request); + return (tokenResponse && tokenResponse.accessToken) || null; } }; diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/constants.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/constants.ts index 430ef07482f1..68d766ae0d1f 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/constants.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/constants.ts @@ -2,7 +2,6 @@ // Licensed under the MIT license. export const DefaultScopeSuffix = "/.default"; - export const imdsHost = "http://169.254.169.254"; export const imdsEndpointPath = "/metadata/identity/oauth2/token"; export const imdsApiVersion = "2018-02-01"; diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/fabricMsi.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/fabricMsi.ts index 135eeda19295..64732bf98052 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/fabricMsi.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/fabricMsi.ts @@ -2,21 +2,43 @@ // Licensed under the MIT license. import https from "https"; -import { createHttpHeaders, PipelineRequestOptions } from "@azure/core-rest-pipeline"; +import { + createHttpHeaders, + createPipelineRequest, + PipelineRequestOptions +} from "@azure/core-rest-pipeline"; import { AccessToken, GetTokenOptions } from "@azure/core-auth"; -import { MSI, MSIConfiguration } from "./models"; +import { TokenResponseParsedBody } from "../../client/identityClient"; import { credentialLogger } from "../../util/logging"; -import { mapScopesToResource, msiGenericGetToken } from "./utils"; +import { MSI, MSIConfiguration } from "./models"; +import { mapScopesToResource } from "./utils"; import { azureFabricVersion } from "./constants"; +// This MSI can be easily tested by deploying a container to Azure Service Fabric with the Dockerfile: +// +// FROM node:12 +// RUN wget https://host.any/path/bash.sh +// CMD ["bash", "bash.sh"] +// +// Where the bash script contains: +// +// curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H "Secret: $IDENTITY_HEADER" +// + const msiName = "ManagedIdentityCredential - Fabric MSI"; const logger = credentialLogger(msiName); -function expiresInParser(requestBody: any): number { - // Parses a string representation of the seconds since epoch into a number value +/** + * Formats the expiration date of the received token into the number of milliseconds between that date and midnight, January 1, 1970. + */ +function expiresOnParser(requestBody: TokenResponseParsedBody): number { + // Parses a string representation of the milliseconds since epoch into a number value return Number(requestBody.expires_on); } +/** + * Generates the options used on the request for an access token. + */ function prepareRequestOptions( scopes: string | string[], clientId?: string @@ -26,7 +48,7 @@ function prepareRequestOptions( throw new Error(`${msiName}: Multiple scopes are not supported.`); } - const queryParameters: any = { + const queryParameters: Record = { resource, "api-version": azureFabricVersion }; @@ -55,17 +77,9 @@ function prepareRequestOptions( }; } -// This credential can be easily tested by deploying a container to Azure Service Fabric with the Dockerfile: -// -// FROM node:12 -// RUN wget https://host.any/path/bash.sh -// CMD ["bash", "bash.sh"] -// -// Where the bash script contains: -// -// curl --insecure $IDENTITY_ENDPOINT'?api-version=2019-07-01-preview&resource=https://vault.azure.net/' -H "Secret: $IDENTITY_HEADER" -// - +/** + * Defines how to determine whether the Azure Service Fabric MSI is available, and also how to retrieve a token from the Azure Service Fabric MSI. + */ export const fabricMsi: MSI = { async isAvailable(scopes): Promise { const resource = mapScopesToResource(scopes); @@ -100,16 +114,20 @@ export const fabricMsi: MSI = { ].join(" ") ); - return msiGenericGetToken( - identityClient, - prepareRequestOptions(scopes, clientId), - expiresInParser, - getTokenOptions, - new https.Agent({ - // This is necessary because Service Fabric provides a self-signed certificate. - // The alternative path is to verify the certificate using the IDENTITY_SERVER_THUMBPRINT env variable. - rejectUnauthorized: false - }) - ); + const request = createPipelineRequest({ + abortSignal: getTokenOptions.abortSignal, + ...prepareRequestOptions(scopes, clientId) + // The service fabric MSI endpoint will be HTTPS (however, the certificate will be self-signed). + // allowInsecureConnection: true + }); + + request.agent = new https.Agent({ + // This is necessary because Service Fabric provides a self-signed certificate. + // The alternative path is to verify the certificate using the IDENTITY_SERVER_THUMBPRINT env variable. + rejectUnauthorized: false + }); + + const tokenResponse = await identityClient.sendTokenRequest(request, expiresOnParser); + return (tokenResponse && tokenResponse.accessToken) || null; } }; diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/imdsMsi.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/imdsMsi.ts index e25fbf3c60d5..af7acd6f38cc 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/imdsMsi.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/imdsMsi.ts @@ -5,23 +5,26 @@ import { delay } from "@azure/core-util"; import { AccessToken, GetTokenOptions } from "@azure/core-auth"; import { createHttpHeaders, - PipelineRequestOptions, createPipelineRequest, + PipelineRequestOptions, RestError } from "@azure/core-rest-pipeline"; import { SpanStatusCode } from "@azure/core-tracing"; -import { IdentityClient } from "../../client/identityClient"; +import { IdentityClient, TokenResponseParsedBody } from "../../client/identityClient"; import { credentialLogger } from "../../util/logging"; +import { AuthenticationError } from "../../errors"; import { createSpan } from "../../util/tracing"; import { imdsApiVersion, imdsEndpointPath, imdsHost } from "./constants"; import { MSI, MSIConfiguration } from "./models"; -import { mapScopesToResource, msiGenericGetToken } from "./utils"; -import { AuthenticationError } from "../../errors"; +import { mapScopesToResource } from "./utils"; const msiName = "ManagedIdentityCredential - IMDS"; const logger = credentialLogger(msiName); -function expiresInParser(requestBody: any): number { +/** + * Formats the expiration date of the received token into the number of milliseconds between that date and midnight, January 1, 1970. + */ +function expiresOnParser(requestBody: TokenResponseParsedBody): number { if (requestBody.expires_on) { // Use the expires_on timestamp if it's available const expires = +requestBody.expires_on * 1000; @@ -39,6 +42,9 @@ function expiresInParser(requestBody: any): number { } } +/** + * Generates the options used on the request for an access token. + */ function prepareRequestOptions( scopes: string | string[], clientId?: string, @@ -58,7 +64,7 @@ function prepareRequestOptions( // Pod Identity will try to process this request even if the Metadata header is missing. // We can exclude the request query to ensure no IMDS endpoint tries to process the ping request. if (!skipQuery) { - const queryParameters: any = { + const queryParameters: Record = { resource, "api-version": imdsApiVersion }; @@ -96,6 +102,9 @@ export const imdsMsiRetryConfig = { intervalIncrement: 2 }; +/** + * Defines how to determine whether the Azure IMDS MSI is available, and also how to retrieve a token from the Azure IMDS MSI. + */ export const imdsMsi: MSI = { async isAvailable( scopes: string | string[], @@ -113,7 +122,7 @@ export const imdsMsi: MSI = { getTokenOptions ); - // if the PodIdenityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist + // if the PodIdentityEndpoint environment variable was set no need to probe the endpoint, it can be assumed to exist if (process.env.AZURE_POD_IDENTITY_AUTHORITY_HOST) { return true; } @@ -188,12 +197,13 @@ export const imdsMsi: MSI = { let nextDelayInMs = imdsMsiRetryConfig.startDelayInMs; for (let retries = 0; retries < imdsMsiRetryConfig.maxRetries; retries++) { try { - return await msiGenericGetToken( - identityClient, - prepareRequestOptions(scopes, clientId), - expiresInParser, - getTokenOptions - ); + const request = createPipelineRequest({ + abortSignal: getTokenOptions.abortSignal, + ...prepareRequestOptions(scopes, clientId), + allowInsecureConnection: true + }); + const tokenResponse = await identityClient.sendTokenRequest(request, expiresOnParser); + return (tokenResponse && tokenResponse.accessToken) || null; } catch (error) { if (error.statusCode === 404) { await delay(nextDelayInMs); diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/index.browser.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/index.browser.ts index eb8715548626..3ad840d2a377 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/index.browser.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/index.browser.ts @@ -3,7 +3,7 @@ import { AccessToken, TokenCredential } from "@azure/core-auth"; -import { TokenCredentialOptions } from "../../client/identityClient"; +import { TokenCredentialOptions } from "../../tokenCredentialOptions"; import { credentialLogger, formatError } from "../../util/logging"; const BrowserNotSupportedError = new Error( diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/index.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/index.ts index f43680ee6c81..0a38b50da906 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/index.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/index.ts @@ -4,7 +4,8 @@ import { SpanStatusCode } from "@azure/core-tracing"; import { AccessToken, GetTokenOptions, TokenCredential } from "@azure/core-auth"; -import { IdentityClient, TokenCredentialOptions } from "../../client/identityClient"; +import { IdentityClient } from "../../client/identityClient"; +import { TokenCredentialOptions } from "../../tokenCredentialOptions"; import { AuthenticationError, CredentialUnavailableError } from "../../errors"; import { credentialLogger, formatSuccess, formatError } from "../../util/logging"; import { appServiceMsi2017 } from "./appServiceMsi2017"; @@ -19,12 +20,11 @@ import { fabricMsi } from "./fabricMsi"; const logger = credentialLogger("ManagedIdentityCredential"); /** - * Attempts authentication using a managed identity that has been assigned - * to the deployment environment. This authentication type works in Azure VMs, - * App Service and Azure Functions applications, and inside of Azure Cloud Shell. + * Attempts authentication using a managed identity available at the deployment environment. + * This authentication type works in Azure VMs, App Service instances, Azure Functions applications, + * Azure Kubernetes Services, Azure Service Fabric instances and inside of the Azure Cloud Shell. * * More information about configuring managed identities can be found here: - * * https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview */ export class ManagedIdentityCredential implements TokenCredential { @@ -84,7 +84,9 @@ export class ManagedIdentityCredential implements TokenCredential { } } - throw new CredentialUnavailableError("ManagedIdentityCredential - No MSI credential available"); + throw new CredentialUnavailableError( + `${ManagedIdentityCredential.name} - No MSI credential available` + ); } private async authenticateManagedIdentity( @@ -93,7 +95,7 @@ export class ManagedIdentityCredential implements TokenCredential { getTokenOptions?: GetTokenOptions ): Promise { const { span, updatedOptions } = createSpan( - "ManagedIdentityCredential-authenticateManagedIdentity", + `${ManagedIdentityCredential.name}.authenticateManagedIdentity`, getTokenOptions ); @@ -135,7 +137,10 @@ export class ManagedIdentityCredential implements TokenCredential { ): Promise { let result: AccessToken | null = null; - const { span, updatedOptions } = createSpan("ManagedIdentityCredential.getToken", options); + const { span, updatedOptions } = createSpan( + `${ManagedIdentityCredential.name}.getToken`, + options + ); try { // isEndpointAvailable can be true, false, or null, @@ -197,7 +202,7 @@ export class ManagedIdentityCredential implements TokenCredential { // we can safely assume the credential is unavailable. if (err.code === "ENETUNREACH") { const error = new CredentialUnavailableError( - `ManagedIdentityCredential is unavailable. Network unreachable. Message: ${err.message}` + `${ManagedIdentityCredential.name}: Unavailable. Network unreachable. Message: ${err.message}` ); logger.getToken.info(formatError(scopes, error)); @@ -208,7 +213,7 @@ export class ManagedIdentityCredential implements TokenCredential { // we can safely assume the credential is unavailable. if (err.code === "EHOSTUNREACH") { const error = new CredentialUnavailableError( - `ManagedIdentityCredential is unavailable. No managed identity endpoint found. Message: ${err.message}` + `${ManagedIdentityCredential.name}: Unavailable. No managed identity endpoint found. Message: ${err.message}` ); logger.getToken.info(formatError(scopes, error)); @@ -219,7 +224,7 @@ export class ManagedIdentityCredential implements TokenCredential { // and it means that the endpoint is working, but that no identity is available. if (err.statusCode === 400) { throw new CredentialUnavailableError( - `ManagedIdentityCredential: The managed identity endpoint is indicating there's no available identity. Message: ${err.message}` + `${ManagedIdentityCredential.name}: The managed identity endpoint is indicating there's no available identity. Message: ${err.message}` ); } @@ -227,13 +232,13 @@ export class ManagedIdentityCredential implements TokenCredential { // This will throw silently during any ChainedTokenCredential. if (err.statusCode === undefined) { throw new CredentialUnavailableError( - `ManagedIdentityCredential authentication failed. Message ${err.message}` + `${ManagedIdentityCredential.name}: Authentication failed. Message ${err.message}` ); } // Any other error should break the chain. throw new AuthenticationError(err.statusCode, { - error: "ManagedIdentityCredential authentication failed.", + error: `${ManagedIdentityCredential.name} authentication failed.`, error_description: err.message }); } finally { diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/models.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/models.ts index b24aef2b5a7b..22713965ad2d 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/models.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/models.ts @@ -2,12 +2,12 @@ // Licensed under the MIT license. import { AccessToken, GetTokenOptions } from "@azure/core-auth"; -import { IdentityClient } from "../../client/identityClient"; +import { IdentityClient, TokenResponseParsedBody } from "../../client/identityClient"; /** * @internal */ -export type MSIExpiresInParser = (requestBody: any) => number; +export type MSIExpiresInParser = (requestBody: TokenResponseParsedBody) => number; /** * @internal diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/tokenExchangeMsi.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/tokenExchangeMsi.ts index eba8fe301447..07d06ec602c2 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/tokenExchangeMsi.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/tokenExchangeMsi.ts @@ -2,30 +2,40 @@ // Licensed under the MIT license. import fs from "fs"; -import { createHttpHeaders, PipelineRequestOptions } from "@azure/core-rest-pipeline"; +import { + createHttpHeaders, + createPipelineRequest, + PipelineRequestOptions +} from "@azure/core-rest-pipeline"; import { AccessToken, GetTokenOptions } from "@azure/core-auth"; import { promisify } from "util"; +import { TokenResponseParsedBody } from "../../client/identityClient"; +import { DefaultAuthorityHost } from "../../constants"; import { credentialLogger } from "../../util/logging"; import { MSI, MSIConfiguration } from "./models"; -import { msiGenericGetToken } from "./utils"; -import { DefaultAuthorityHost } from "../../constants"; const msiName = "ManagedIdentityCredential - Token Exchange"; const logger = credentialLogger(msiName); const readFileAsync = promisify(fs.readFile); -function expiresInParser(requestBody: any): number { +/** + * Formats the expiration date of the received token into the number of milliseconds between that date and midnight, January 1, 1970. + */ +function expiresOnParser(requestBody: TokenResponseParsedBody): number { // Parses a string representation of the seconds since epoch into a number value return Number(requestBody.expires_on); } +/** + * Generates the options used on the request for an access token. + */ function prepareRequestOptions( scopes: string | string[], clientAssertion: string, - clientId?: string + clientId: string ): PipelineRequestOptions { - const bodyParams: any = { + const bodyParams: Record = { scope: Array.isArray(scopes) ? scopes.join(" ") : scopes, client_assertion: clientAssertion, client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", @@ -49,6 +59,9 @@ function prepareRequestOptions( }; } +/** + * Defines how to determine whether the token exchange MSI is available, and also how to retrieve a token from the token exchange MSI. + */ export function tokenExchangeMsi(): MSI { const azureFederatedTokenFilePath = process.env.AZURE_FEDERATED_TOKEN_FILE; let azureFederatedTokenFileContent: string | undefined = undefined; @@ -105,12 +118,14 @@ export function tokenExchangeMsi(): MSI { ); } - return msiGenericGetToken( - identityClient, - prepareRequestOptions(scopes, assertion, clientId || process.env.AZURE_CLIENT_ID), - expiresInParser, - getTokenOptions - ); + const request = createPipelineRequest({ + abortSignal: getTokenOptions.abortSignal, + ...prepareRequestOptions(scopes, assertion, clientId || process.env.AZURE_CLIENT_ID!), + // Generally, MSI endpoints use the HTTP protocol, without transport layer security (TLS). + allowInsecureConnection: true + }); + const tokenResponse = await identityClient.sendTokenRequest(request, expiresOnParser); + return (tokenResponse && tokenResponse.accessToken) || null; } }; } diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/utils.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/utils.ts index cd42c22df699..8abb245962ee 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/utils.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/utils.ts @@ -1,15 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { AccessToken, GetTokenOptions } from "@azure/core-auth"; -import { PipelineRequestOptions, createPipelineRequest } from "@azure/core-rest-pipeline"; -import { Agent } from "http"; -import { IdentityClient } from "../../client/identityClient"; import { DefaultScopeSuffix } from "./constants"; -import { MSIExpiresInParser } from "./models"; /** - * Most MSIs send requests to the IMDS endpoint, or a similar endpoint. These are GET requests that require sending a `resource` parameter on the query. + * Most MSIs send requests to the IMDS endpoint, or a similar endpoint. + * These are GET requests that require sending a `resource` parameter on the query. * This resource can be derived from the scopes received through the getToken call, as long as only one scope is received. * Multiple scopes assume that the resulting token will have access to multiple resources, which won't be the case. * @@ -34,24 +30,3 @@ export function mapScopesToResource(scopes: string | string[]): string | undefin return scope.substr(0, scope.lastIndexOf(DefaultScopeSuffix)); } - -export async function msiGenericGetToken( - identityClient: IdentityClient, - requestOptions: PipelineRequestOptions, - expiresInParser: MSIExpiresInParser | undefined, - getTokenOptions: GetTokenOptions = {}, - agent?: Agent -): Promise { - const request = createPipelineRequest({ - abortSignal: getTokenOptions.abortSignal, - ...requestOptions, - allowInsecureConnection: true - }); - - if (agent) { - request.agent = agent; - } - - const tokenResponse = await identityClient.sendTokenRequest(request, expiresInParser); - return (tokenResponse && tokenResponse.accessToken) || null; -} diff --git a/sdk/identity/identity/src/credentials/onBehalfOfCredentialOptions.ts b/sdk/identity/identity/src/credentials/onBehalfOfCredentialOptions.ts index 7c374e1c86ad..2dcf615518c0 100644 --- a/sdk/identity/identity/src/credentials/onBehalfOfCredentialOptions.ts +++ b/sdk/identity/identity/src/credentials/onBehalfOfCredentialOptions.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { CredentialPersistenceOptions } from "./credentialPersistenceOptions"; /** diff --git a/sdk/identity/identity/src/credentials/usernamePasswordCredential.browser.ts b/sdk/identity/identity/src/credentials/usernamePasswordCredential.browser.ts index 53a8932005ff..122f18774bc0 100644 --- a/sdk/identity/identity/src/credentials/usernamePasswordCredential.browser.ts +++ b/sdk/identity/identity/src/credentials/usernamePasswordCredential.browser.ts @@ -4,7 +4,8 @@ import { TokenCredential, GetTokenOptions, AccessToken } from "@azure/core-auth"; import { createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline"; import { SpanStatusCode } from "@azure/core-tracing"; -import { TokenCredentialOptions, IdentityClient } from "../client/identityClient"; +import { IdentityClient } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { credentialLogger, formatSuccess, formatError } from "../util/logging"; import { getIdentityTokenEndpointSuffix } from "../util/identityTokenEndpoint"; import { createSpan } from "../util/tracing"; diff --git a/sdk/identity/identity/src/credentials/usernamePasswordCredentialOptions.ts b/sdk/identity/identity/src/credentials/usernamePasswordCredentialOptions.ts index 5abe8010dd14..7d477c1e66b6 100644 --- a/sdk/identity/identity/src/credentials/usernamePasswordCredentialOptions.ts +++ b/sdk/identity/identity/src/credentials/usernamePasswordCredentialOptions.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { TokenCredentialOptions } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { CredentialPersistenceOptions } from "./credentialPersistenceOptions"; /** diff --git a/sdk/identity/identity/src/credentials/visualStudioCodeCredential.ts b/sdk/identity/identity/src/credentials/visualStudioCodeCredential.ts index 28597b3a3097..c712c726bd83 100644 --- a/sdk/identity/identity/src/credentials/visualStudioCodeCredential.ts +++ b/sdk/identity/identity/src/credentials/visualStudioCodeCredential.ts @@ -7,13 +7,14 @@ import fs from "fs"; import os from "os"; import path from "path"; -import { CredentialUnavailableError } from "../errors"; -import { IdentityClient, TokenCredentialOptions } from "../client/identityClient"; import { AzureAuthorityHosts } from "../constants"; import { checkTenantId } from "../util/checkTenantId"; -import { credentialLogger, formatError, formatSuccess } from "../util/logging"; +import { CredentialUnavailableError } from "../errors"; +import { IdentityClient } from "../client/identityClient"; +import { TokenCredentialOptions } from "../tokenCredentialOptions"; import { processMultiTenantRequest } from "../util/validateMultiTenant"; import { VSCodeCredentialFinder } from "./visualStudioCodeCredentialPlugin"; +import { credentialLogger, formatError, formatSuccess } from "../util/logging"; const CommonTenantId = "common"; const AzureAccountClientId = "aebc6443-996d-45c2-90f0-388ff96faa56"; // VSC: 'aebc6443-996d-45c2-90f0-388ff96faa56' diff --git a/sdk/identity/identity/src/index.ts b/sdk/identity/identity/src/index.ts index 6b23852bf060..9a445b0745c0 100644 --- a/sdk/identity/identity/src/index.ts +++ b/sdk/identity/identity/src/index.ts @@ -22,7 +22,7 @@ export { export { AuthenticationRecord } from "./msal/types"; export { serializeAuthenticationRecord, deserializeAuthenticationRecord } from "./msal/utils"; -export { TokenCredentialOptions } from "./client/identityClient"; +export { TokenCredentialOptions } from "./tokenCredentialOptions"; // TODO: Export again once we're ready to release this feature. // export { RegionalAuthority } from "./regionalAuthority"; diff --git a/sdk/identity/identity/src/msal/browserFlows/msalAuthCode.ts b/sdk/identity/identity/src/msal/browserFlows/msalAuthCode.ts index 4e2b14797e04..692c1b3beb9a 100644 --- a/sdk/identity/identity/src/msal/browserFlows/msalAuthCode.ts +++ b/sdk/identity/identity/src/msal/browserFlows/msalAuthCode.ts @@ -2,14 +2,13 @@ // Licensed under the MIT license. import * as msalBrowser from "@azure/msal-browser"; - import { AccessToken } from "@azure/core-auth"; import { AuthenticationRequiredError } from "../../errors"; import { defaultLoggerCallback, msalToPublic, publicToMsal } from "../utils"; import { AuthenticationRecord } from "../types"; import { CredentialFlowGetTokenOptions } from "../credentials"; -import { MsalBrowserFlowOptions, MsalBrowser } from "./browserCommon"; +import { MsalBrowserFlowOptions, MsalBrowser } from "./msalBrowserCommon"; // We keep a copy of the redirect hash. const redirectHash = self.location.hash; diff --git a/sdk/identity/identity/src/msal/browserFlows/browserCommon.ts b/sdk/identity/identity/src/msal/browserFlows/msalBrowserCommon.ts similarity index 99% rename from sdk/identity/identity/src/msal/browserFlows/browserCommon.ts rename to sdk/identity/identity/src/msal/browserFlows/msalBrowserCommon.ts index e5c9fa89eedc..f82e6289caae 100644 --- a/sdk/identity/identity/src/msal/browserFlows/browserCommon.ts +++ b/sdk/identity/identity/src/msal/browserFlows/msalBrowserCommon.ts @@ -2,7 +2,6 @@ // Licensed under the MIT license. import * as msalBrowser from "@azure/msal-browser"; - import { AccessToken } from "@azure/core-auth"; import { DefaultTenantId } from "../../constants"; diff --git a/sdk/identity/identity/src/msal/nodeFlows/msalAuthorizationCode.ts b/sdk/identity/identity/src/msal/nodeFlows/msalAuthorizationCode.ts index 0b6dc98fc471..7ade1f173e24 100644 --- a/sdk/identity/identity/src/msal/nodeFlows/msalAuthorizationCode.ts +++ b/sdk/identity/identity/src/msal/nodeFlows/msalAuthorizationCode.ts @@ -4,7 +4,7 @@ import { AccessToken } from "@azure/core-auth"; import { credentialLogger } from "../../util/logging"; import { CredentialFlowGetTokenOptions } from "../credentials"; -import { MsalNodeOptions, MsalNode } from "./nodeCommon"; +import { MsalNodeOptions, MsalNode } from "./msalNodeCommon"; /** * Options that can be passed to configure MSAL to handle authentication through opening a browser window. diff --git a/sdk/identity/identity/src/msal/nodeFlows/msalClientCertificate.ts b/sdk/identity/identity/src/msal/nodeFlows/msalClientCertificate.ts index d25abece63da..6a125d4e54b3 100644 --- a/sdk/identity/identity/src/msal/nodeFlows/msalClientCertificate.ts +++ b/sdk/identity/identity/src/msal/nodeFlows/msalClientCertificate.ts @@ -6,7 +6,7 @@ import { createHash } from "crypto"; import { promisify } from "util"; import { AccessToken } from "@azure/core-auth"; -import { MsalNodeOptions, MsalNode } from "./nodeCommon"; +import { MsalNodeOptions, MsalNode } from "./msalNodeCommon"; import { formatError } from "../../util/logging"; import { CredentialFlowGetTokenOptions } from "../credentials"; import { ClientCertificateCredentialPEMConfiguration } from "../../credentials/clientCertificateCredential"; diff --git a/sdk/identity/identity/src/msal/nodeFlows/msalClientSecret.ts b/sdk/identity/identity/src/msal/nodeFlows/msalClientSecret.ts index 9af4dfa6070d..a7cffde4fb1b 100644 --- a/sdk/identity/identity/src/msal/nodeFlows/msalClientSecret.ts +++ b/sdk/identity/identity/src/msal/nodeFlows/msalClientSecret.ts @@ -4,7 +4,7 @@ import { AccessToken } from "@azure/core-auth"; import { CredentialFlowGetTokenOptions } from "../credentials"; -import { MsalNodeOptions, MsalNode } from "./nodeCommon"; +import { MsalNodeOptions, MsalNode } from "./msalNodeCommon"; /** * Options that can be passed to configure MSAL to handle client secrets. diff --git a/sdk/identity/identity/src/msal/nodeFlows/msalDeviceCode.ts b/sdk/identity/identity/src/msal/nodeFlows/msalDeviceCode.ts index bf0b3e329d88..89ba9af04f3d 100644 --- a/sdk/identity/identity/src/msal/nodeFlows/msalDeviceCode.ts +++ b/sdk/identity/identity/src/msal/nodeFlows/msalDeviceCode.ts @@ -2,12 +2,11 @@ // Licensed under the MIT license. import * as msalNode from "@azure/msal-node"; - import { AccessToken } from "@azure/core-auth"; import { DeviceCodePromptCallback } from "../../credentials/deviceCodeCredentialOptions"; import { CredentialFlowGetTokenOptions } from "../credentials"; -import { MsalNodeOptions, MsalNode } from "./nodeCommon"; +import { MsalNodeOptions, MsalNode } from "./msalNodeCommon"; /** * Options that can be passed to configure MSAL to handle authentication through device codes. diff --git a/sdk/identity/identity/src/msal/nodeFlows/nodeCommon.ts b/sdk/identity/identity/src/msal/nodeFlows/msalNodeCommon.ts similarity index 98% rename from sdk/identity/identity/src/msal/nodeFlows/nodeCommon.ts rename to sdk/identity/identity/src/msal/nodeFlows/msalNodeCommon.ts index e5246c63ca36..dd142f3e9a85 100644 --- a/sdk/identity/identity/src/msal/nodeFlows/nodeCommon.ts +++ b/sdk/identity/identity/src/msal/nodeFlows/msalNodeCommon.ts @@ -3,12 +3,12 @@ import * as msalNode from "@azure/msal-node"; import * as msalCommon from "@azure/msal-common"; - import { AccessToken, GetTokenOptions } from "@azure/core-auth"; import { AbortSignalLike } from "@azure/abort-controller"; +import { IdentityClient } from "../../client/identityClient"; +import { TokenCredentialOptions } from "../../tokenCredentialOptions"; import { DeveloperSignOnClientId } from "../../constants"; -import { IdentityClient, TokenCredentialOptions } from "../../client/identityClient"; import { resolveTenantId } from "../../util/resolveTenantId"; import { AuthenticationRequiredError } from "../../errors"; import { CredentialFlowGetTokenOptions } from "../credentials"; diff --git a/sdk/identity/identity/src/msal/nodeFlows/msalOnBehalfOf.ts b/sdk/identity/identity/src/msal/nodeFlows/msalOnBehalfOf.ts index 1713b60b18e6..460d3254c587 100644 --- a/sdk/identity/identity/src/msal/nodeFlows/msalOnBehalfOf.ts +++ b/sdk/identity/identity/src/msal/nodeFlows/msalOnBehalfOf.ts @@ -2,10 +2,11 @@ // Licensed under the MIT license. import { AccessToken } from "@azure/core-auth"; + import { formatError } from "../../util/logging"; import { CredentialFlowGetTokenOptions } from "../credentials"; import { parseCertificate } from "./msalClientCertificate"; -import { MsalNodeOptions, MsalNode } from "./nodeCommon"; +import { MsalNodeOptions, MsalNode } from "./msalNodeCommon"; /** * Options that can be passed to configure MSAL to handle On-Behalf-Of authentication requests. diff --git a/sdk/identity/identity/src/msal/nodeFlows/msalOpenBrowser.ts b/sdk/identity/identity/src/msal/nodeFlows/msalOpenBrowser.ts index 58bab4ec95a4..18d94581c10e 100644 --- a/sdk/identity/identity/src/msal/nodeFlows/msalOpenBrowser.ts +++ b/sdk/identity/identity/src/msal/nodeFlows/msalOpenBrowser.ts @@ -12,9 +12,9 @@ import stoppable from "stoppable"; import { credentialLogger, formatError, formatSuccess } from "../../util/logging"; import { CredentialUnavailableError } from "../../errors"; -import { MsalNodeOptions, MsalNode } from "./nodeCommon"; -import { msalToPublic } from "../utils"; +import { MsalNodeOptions, MsalNode } from "./msalNodeCommon"; import { CredentialFlowGetTokenOptions } from "../credentials"; +import { msalToPublic } from "../utils"; /** * Options that can be passed to configure MSAL to handle authentication through opening a browser window. diff --git a/sdk/identity/identity/src/msal/nodeFlows/msalUsernamePassword.ts b/sdk/identity/identity/src/msal/nodeFlows/msalUsernamePassword.ts index 59a3b0a27155..6bbc3ced2615 100644 --- a/sdk/identity/identity/src/msal/nodeFlows/msalUsernamePassword.ts +++ b/sdk/identity/identity/src/msal/nodeFlows/msalUsernamePassword.ts @@ -2,10 +2,9 @@ // Licensed under the MIT license. import * as msalNode from "@azure/msal-node"; - import { AccessToken } from "@azure/core-auth"; -import { MsalNodeOptions, MsalNode } from "./nodeCommon"; +import { MsalNodeOptions, MsalNode } from "./msalNodeCommon"; import { CredentialFlowGetTokenOptions } from "../credentials"; /** diff --git a/sdk/identity/identity/src/plugins/consumer.ts b/sdk/identity/identity/src/plugins/consumer.ts index 5041c7330fea..36c61fcd02b9 100644 --- a/sdk/identity/identity/src/plugins/consumer.ts +++ b/sdk/identity/identity/src/plugins/consumer.ts @@ -2,7 +2,7 @@ // Licensed under the MIT license. import { AzurePluginContext, IdentityPlugin } from "./provider"; -import { msalNodeFlowCacheControl } from "../msal/nodeFlows/nodeCommon"; +import { msalNodeFlowCacheControl } from "../msal/nodeFlows/msalNodeCommon"; import { vsCodeCredentialControl } from "../credentials/visualStudioCodeCredential"; /** diff --git a/sdk/identity/identity/src/tokenCredentialOptions.ts b/sdk/identity/identity/src/tokenCredentialOptions.ts new file mode 100644 index 000000000000..bd20c4d7198c --- /dev/null +++ b/sdk/identity/identity/src/tokenCredentialOptions.ts @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { CommonClientOptions } from "@azure/core-client"; + +/** + * Provides options to configure how the Identity library makes authentication + * requests to Azure Active Directory. + */ +export interface TokenCredentialOptions extends CommonClientOptions { + /** + * The authority host to use for authentication requests. + * Possible values are available through {@link AzureAuthorityHosts}. + * The default is "https://login.microsoftonline.com". + */ + authorityHost?: string; +} diff --git a/sdk/identity/identity/test/internal/node/clientCertificateCredential.spec.ts b/sdk/identity/identity/test/internal/node/clientCertificateCredential.spec.ts index 285763044780..0d31079a54e8 100644 --- a/sdk/identity/identity/test/internal/node/clientCertificateCredential.spec.ts +++ b/sdk/identity/identity/test/internal/node/clientCertificateCredential.spec.ts @@ -11,7 +11,7 @@ import { env, isPlaybackMode, delay } from "@azure-tools/test-recorder"; import { ConfidentialClientApplication } from "@azure/msal-node"; import { ClientCertificateCredential } from "../../../src"; import { MsalTestCleanup, msalNodeTestSetup } from "../../msalTestUtils"; -import { MsalNode } from "../../../src/msal/nodeFlows/nodeCommon"; +import { MsalNode } from "../../../src/msal/nodeFlows/msalNodeCommon"; import { Context } from "mocha"; const ASSET_PATH = "assets"; diff --git a/sdk/identity/identity/test/internal/node/clientSecretCredential.spec.ts b/sdk/identity/identity/test/internal/node/clientSecretCredential.spec.ts index 0394ce916a2a..4cd9308118f6 100644 --- a/sdk/identity/identity/test/internal/node/clientSecretCredential.spec.ts +++ b/sdk/identity/identity/test/internal/node/clientSecretCredential.spec.ts @@ -10,7 +10,7 @@ import { env, delay } from "@azure-tools/test-recorder"; import { ConfidentialClientApplication } from "@azure/msal-node"; import { ClientSecretCredential } from "../../../src"; import { MsalTestCleanup, msalNodeTestSetup } from "../../msalTestUtils"; -import { MsalNode } from "../../../src/msal/nodeFlows/nodeCommon"; +import { MsalNode } from "../../../src/msal/nodeFlows/msalNodeCommon"; import { Context } from "mocha"; describe("ClientSecretCredential (internal)", function() { diff --git a/sdk/identity/identity/test/internal/node/deviceCodeCredential.spec.ts b/sdk/identity/identity/test/internal/node/deviceCodeCredential.spec.ts index 12170b0ac064..bf164317ca78 100644 --- a/sdk/identity/identity/test/internal/node/deviceCodeCredential.spec.ts +++ b/sdk/identity/identity/test/internal/node/deviceCodeCredential.spec.ts @@ -9,7 +9,7 @@ import { PublicClientApplication } from "@azure/msal-node"; import { env, isLiveMode } from "@azure-tools/test-recorder"; import { DeviceCodeCredential } from "../../../src"; import { MsalTestCleanup, msalNodeTestSetup } from "../../msalTestUtils"; -import { MsalNode } from "../../../src/msal/nodeFlows/nodeCommon"; +import { MsalNode } from "../../../src/msal/nodeFlows/msalNodeCommon"; import { Context } from "mocha"; describe("DeviceCodeCredential (internal)", function() { diff --git a/sdk/identity/identity/test/internal/node/environmentCredential.spec.ts b/sdk/identity/identity/test/internal/node/environmentCredential.spec.ts index 61026912a69a..a1dffff3a8a7 100644 --- a/sdk/identity/identity/test/internal/node/environmentCredential.spec.ts +++ b/sdk/identity/identity/test/internal/node/environmentCredential.spec.ts @@ -8,7 +8,7 @@ import { assert } from "chai"; import { ConfidentialClientApplication } from "@azure/msal-node"; import { EnvironmentCredential } from "../../../src"; import { MsalTestCleanup, msalNodeTestSetup } from "../../msalTestUtils"; -import { MsalNode } from "../../../src/msal/nodeFlows/nodeCommon"; +import { MsalNode } from "../../../src/msal/nodeFlows/msalNodeCommon"; import { Context } from "mocha"; describe("EnvironmentCredential (internal)", function() { diff --git a/sdk/identity/identity/test/internal/node/usernamePasswordCredential.spec.ts b/sdk/identity/identity/test/internal/node/usernamePasswordCredential.spec.ts index a2fa3f00cd83..4ad558388773 100644 --- a/sdk/identity/identity/test/internal/node/usernamePasswordCredential.spec.ts +++ b/sdk/identity/identity/test/internal/node/usernamePasswordCredential.spec.ts @@ -10,7 +10,7 @@ import { env, isLiveMode } from "@azure-tools/test-recorder"; import { PublicClientApplication } from "@azure/msal-node"; import { UsernamePasswordCredential } from "../../../src"; import { MsalTestCleanup, msalNodeTestSetup } from "../../msalTestUtils"; -import { MsalNode } from "../../../src/msal/nodeFlows/nodeCommon"; +import { MsalNode } from "../../../src/msal/nodeFlows/msalNodeCommon"; describe("UsernamePasswordCredential (internal)", function() { let cleanup: MsalTestCleanup; diff --git a/sdk/identity/identity/samples/manual/README.md b/sdk/identity/identity/test/manual/authorization-code-credential/README.md similarity index 90% rename from sdk/identity/identity/samples/manual/README.md rename to sdk/identity/identity/test/manual/authorization-code-credential/README.md index 5682d4e184db..9c2f6fa0ab43 100644 --- a/sdk/identity/identity/samples/manual/README.md +++ b/sdk/identity/identity/test/manual/authorization-code-credential/README.md @@ -23,10 +23,10 @@ On the Azure Portal, navigate to your app registration. On the side panel, selec - Under "Supported Account Types", select `Accounts in any organizational directory (Any Azure AD directory - Multitenant)` . - Under "Platform Configurations", add a platform and select "Web". Then add `http://localhost:8080/authresponse` as the redirect URI. Then click "Configure". -4. Navigate to the `samples/manual` folder +4. Navigate to the `test/manual/authorization-code-credential` folder ```bash -cd /sdk/identity/identity/samples/manual +cd /sdk/identity/identity/test/manual/authorization-code-credential ``` 5. Copy the `sample.env` into a file named `.env` in this folder and make sure to fill the values accordingly. diff --git a/sdk/identity/identity/samples/manual/authorizationCodeSample.ts b/sdk/identity/identity/test/manual/authorization-code-credential/authorizationCodeSample.ts similarity index 98% rename from sdk/identity/identity/samples/manual/authorizationCodeSample.ts rename to sdk/identity/identity/test/manual/authorization-code-credential/authorizationCodeSample.ts index 7fe91eb7ff99..0873278bc9fa 100644 --- a/sdk/identity/identity/samples/manual/authorizationCodeSample.ts +++ b/sdk/identity/identity/test/manual/authorization-code-credential/authorizationCodeSample.ts @@ -4,7 +4,7 @@ import { Server } from "http"; // NOTE: When using this code, you must change the module below to "@azure/identity" -import { AuthorizationCodeCredential } from "../../src/credentials/authorizationCodeCredential"; +import { AuthorizationCodeCredential } from "@azure/identity"; // You will need to install these external dependencies with NPM: import open from "open"; diff --git a/sdk/identity/identity/samples/manual/package.json b/sdk/identity/identity/test/manual/authorization-code-credential/package.json similarity index 86% rename from sdk/identity/identity/samples/manual/package.json rename to sdk/identity/identity/test/manual/authorization-code-credential/package.json index 1828f976beb8..30c44ce78d6e 100644 --- a/sdk/identity/identity/samples/manual/package.json +++ b/sdk/identity/identity/test/manual/authorization-code-credential/package.json @@ -15,5 +15,8 @@ "open": "^8.2.1", "qs": "^6.10.1", "ts-node": "latest" + }, + "dependencies": { + "@azure/identity": "^2.0.1" } } diff --git a/sdk/identity/identity/samples/manual/sample.env b/sdk/identity/identity/test/manual/authorization-code-credential/sample.env similarity index 100% rename from sdk/identity/identity/samples/manual/sample.env rename to sdk/identity/identity/test/manual/authorization-code-credential/sample.env diff --git a/sdk/identity/identity/test/manual/dist/index.html b/sdk/identity/identity/test/manual/dist/index.html deleted file mode 100644 index b935a6357b41..000000000000 --- a/sdk/identity/identity/test/manual/dist/index.html +++ /dev/null @@ -1,6 +0,0 @@ - - -
- - - diff --git a/sdk/identity/identity/test/manual/README.md b/sdk/identity/identity/test/manual/interactive-browser-credential/README.md similarity index 100% rename from sdk/identity/identity/test/manual/README.md rename to sdk/identity/identity/test/manual/interactive-browser-credential/README.md diff --git a/sdk/identity/identity/test/manual/nodeTest.js b/sdk/identity/identity/test/manual/interactive-browser-credential/nodeTest.js similarity index 100% rename from sdk/identity/identity/test/manual/nodeTest.js rename to sdk/identity/identity/test/manual/interactive-browser-credential/nodeTest.js diff --git a/sdk/identity/identity/test/manual/nodeTestSilent.js b/sdk/identity/identity/test/manual/interactive-browser-credential/nodeTestSilent.js similarity index 100% rename from sdk/identity/identity/test/manual/nodeTestSilent.js rename to sdk/identity/identity/test/manual/interactive-browser-credential/nodeTestSilent.js diff --git a/sdk/identity/identity/test/manual/package.json b/sdk/identity/identity/test/manual/interactive-browser-credential/package.json similarity index 100% rename from sdk/identity/identity/test/manual/package.json rename to sdk/identity/identity/test/manual/interactive-browser-credential/package.json diff --git a/sdk/identity/identity/test/manual/src/index.tsx b/sdk/identity/identity/test/manual/interactive-browser-credential/src/index.tsx similarity index 100% rename from sdk/identity/identity/test/manual/src/index.tsx rename to sdk/identity/identity/test/manual/interactive-browser-credential/src/index.tsx diff --git a/sdk/identity/identity/test/manual/tsconfig.json b/sdk/identity/identity/test/manual/interactive-browser-credential/tsconfig.json similarity index 100% rename from sdk/identity/identity/test/manual/tsconfig.json rename to sdk/identity/identity/test/manual/interactive-browser-credential/tsconfig.json diff --git a/sdk/identity/identity/test/manual/webpack.config.js b/sdk/identity/identity/test/manual/interactive-browser-credential/webpack.config.js similarity index 100% rename from sdk/identity/identity/test/manual/webpack.config.js rename to sdk/identity/identity/test/manual/interactive-browser-credential/webpack.config.js