From 00827b4996bb77bc8f4eea386c7b0e02e3b4f42f Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Tue, 3 Aug 2021 07:11:16 -0700 Subject: [PATCH 01/18] application credential --- .../src/credentials/applicationCredential.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 sdk/identity/identity/src/credentials/applicationCredential.ts diff --git a/sdk/identity/identity/src/credentials/applicationCredential.ts b/sdk/identity/identity/src/credentials/applicationCredential.ts new file mode 100644 index 000000000000..849715148788 --- /dev/null +++ b/sdk/identity/identity/src/credentials/applicationCredential.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { AccessToken, GetTokenOptions, TokenCredential } from "@azure/core-auth"; +// import { EnvironmentCredential } from "./environmentCredential"; + +// import { ChainedTokenCredential } from "./chainedTokenCredential"; + +export class ApplicationCredential implements TokenCredential { + constructor(clientId: string, tenantId: string, authorityHost?: string) { + clientId = clientId; + tenantId = tenantId; + authorityHost = authorityHost; + //new EnvironmentCredential({authorityHost}) + } + getToken(scopes: string | string[], options?: GetTokenOptions): Promise { + throw new Error("Method not implemented."); + } +} From c8c4c8828b09cc652ca7103a7a4b0d4bb384efc4 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Tue, 3 Aug 2021 07:12:15 -0700 Subject: [PATCH 02/18] application credential --- .../src/credentials/applicationCredential.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sdk/identity/identity/src/credentials/applicationCredential.ts b/sdk/identity/identity/src/credentials/applicationCredential.ts index 849715148788..01c004af4c55 100644 --- a/sdk/identity/identity/src/credentials/applicationCredential.ts +++ b/sdk/identity/identity/src/credentials/applicationCredential.ts @@ -2,7 +2,9 @@ // Licensed under the MIT license. import { AccessToken, GetTokenOptions, TokenCredential } from "@azure/core-auth"; -// import { EnvironmentCredential } from "./environmentCredential"; +import { TokenCredentialOptions } from "../client/identityClient"; +import { EnvironmentCredential } from "./environmentCredential"; +import { ManagedIdentityCredential } from "./managedIdentityCredential"; // import { ChainedTokenCredential } from "./chainedTokenCredential"; @@ -11,9 +13,17 @@ export class ApplicationCredential implements TokenCredential { clientId = clientId; tenantId = tenantId; authorityHost = authorityHost; - //new EnvironmentCredential({authorityHost}) + new ManagedIdentityCredential(clientId); + new EnvironmentCredential({ authorityHost }); } getToken(scopes: string | string[], options?: GetTokenOptions): Promise { throw new Error("Method not implemented."); } } + +export interface ApplicationCredentialOptions extends TokenCredentialOptions { + /** + * Optionally pass in a Tenant ID to be used as part of the credential + */ + secretId?: string; +} From 5c57432cb326822bb0a130379da91b91158f44b7 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Tue, 3 Aug 2021 11:56:20 -0700 Subject: [PATCH 03/18] application credential creation --- .../src/credentials/applicationCredential.ts | 74 ++++++++++++++----- .../src/credentials/defaultAzureCredential.ts | 2 +- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/sdk/identity/identity/src/credentials/applicationCredential.ts b/sdk/identity/identity/src/credentials/applicationCredential.ts index 01c004af4c55..2026c7aae807 100644 --- a/sdk/identity/identity/src/credentials/applicationCredential.ts +++ b/sdk/identity/identity/src/credentials/applicationCredential.ts @@ -1,29 +1,69 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { AccessToken, GetTokenOptions, TokenCredential } from "@azure/core-auth"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { TokenCredential } from "@azure/core-auth"; + import { TokenCredentialOptions } from "../client/identityClient"; + +import { ChainedTokenCredential } from "./chainedTokenCredential"; + import { EnvironmentCredential } from "./environmentCredential"; -import { ManagedIdentityCredential } from "./managedIdentityCredential"; +import { CredentialPersistenceOptions } from "./credentialPersistenceOptions"; +import { DefaultManagedIdentityCredential } from "./defaultAzureCredential"; -// import { ChainedTokenCredential } from "./chainedTokenCredential"; +/** + * Provides options to configure the {@link ApplicationCredential} class. + */ +export interface ApplicationCredentialOptions + extends TokenCredentialOptions, + CredentialPersistenceOptions { + /** + * Optionally pass in a user assigned client ID to be used by the {@link ManagedIdentityCredential}. + * This client ID can also be passed through to the {@link ManagedIdentityCredential} through the environment variable: AZURE_CLIENT_ID. + */ + managedIdentityClientId?: string; +} -export class ApplicationCredential implements TokenCredential { - constructor(clientId: string, tenantId: string, authorityHost?: string) { - clientId = clientId; - tenantId = tenantId; - authorityHost = authorityHost; - new ManagedIdentityCredential(clientId); - new EnvironmentCredential({ authorityHost }); - } - getToken(scopes: string | string[], options?: GetTokenOptions): Promise { - throw new Error("Method not implemented."); - } +/** + * The type of a class that implements TokenCredential and accepts + * `ApplicationCredentialOptions`. + */ +interface ApplicationCredentialConstructor { + new (options?: ApplicationCredentialOptions): TokenCredential; } -export interface ApplicationCredentialOptions extends TokenCredentialOptions { +export const ApplicationCredentials: ApplicationCredentialConstructor[] = [ + EnvironmentCredential, + DefaultManagedIdentityCredential +]; + +/** + * 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: + * + * - {@link EnvironmentCredential} + * - {@link ManagedIdentityCredential} + + * + * Consult the documentation of these credential types for more information + * on how they attempt authentication. + * + * Azure Identity extensions may add credential types to the default credential + * stack. + */ +export class ApplicationCredential extends ChainedTokenCredential { /** - * Optionally pass in a Tenant ID to be used as part of the credential + * Creates an instance of the ApplicationCredential class. + * + * @param options - Optional parameters. See {@link ApplicationCredentialOptions}. */ - secretId?: string; + constructor(options?: ApplicationCredentialOptions) { + super(...ApplicationCredentials.map((ctor) => new ctor(options))); + this.UnavailableMessage = + "ApplicationCredential => failed to retrieve a token from the included credentials"; + } } diff --git a/sdk/identity/identity/src/credentials/defaultAzureCredential.ts b/sdk/identity/identity/src/credentials/defaultAzureCredential.ts index 1bbbda2020b5..e67d383c6e0b 100644 --- a/sdk/identity/identity/src/credentials/defaultAzureCredential.ts +++ b/sdk/identity/identity/src/credentials/defaultAzureCredential.ts @@ -46,7 +46,7 @@ interface DefaultCredentialConstructor { * * @internal */ -class DefaultManagedIdentityCredential extends ManagedIdentityCredential { +export class DefaultManagedIdentityCredential extends ManagedIdentityCredential { constructor(options?: DefaultAzureCredentialOptions) { const managedIdentityClientId = options?.managedIdentityClientId ?? process.env.AZURE_CLIENT_ID; if (managedIdentityClientId !== undefined) { From ae0e1e34184bd581185ba55b748c6a414a240790 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Tue, 3 Aug 2021 17:01:56 -0700 Subject: [PATCH 04/18] export ApplicationCredential and update api review --- sdk/identity/identity/review/identity.api.md | 10 ++++++++++ sdk/identity/identity/src/index.ts | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/sdk/identity/identity/review/identity.api.md b/sdk/identity/identity/review/identity.api.md index 05d9b48d273e..46e790880c93 100644 --- a/sdk/identity/identity/review/identity.api.md +++ b/sdk/identity/identity/review/identity.api.md @@ -21,6 +21,16 @@ export class AggregateAuthenticationError extends Error { // @public export const AggregateAuthenticationErrorName = "AggregateAuthenticationError"; +// @public +export class ApplicationCredential extends ChainedTokenCredential { + constructor(options?: ApplicationCredentialOptions); +} + +// @public +export interface ApplicationCredentialOptions extends TokenCredentialOptions, CredentialPersistenceOptions { + managedIdentityClientId?: string; +} + // @public export class AuthenticationError extends Error { constructor(statusCode: number, errorBody: object | string | undefined | null); diff --git a/sdk/identity/identity/src/index.ts b/sdk/identity/identity/src/index.ts index 55ff135f90e7..1fdf0046f06c 100644 --- a/sdk/identity/identity/src/index.ts +++ b/sdk/identity/identity/src/index.ts @@ -49,6 +49,10 @@ export { UsernamePasswordCredentialOptions } from "./credentials/usernamePasswor export { AuthorizationCodeCredential } from "./credentials/authorizationCodeCredential"; export { AzurePowerShellCredential } from "./credentials/azurePowerShellCredential"; export { AzurePowerShellCredentialOptions } from "./credentials/azurePowerShellCredentialOptions"; +export { + ApplicationCredential, + ApplicationCredentialOptions +} from "./credentials/applicationCredential"; export { VisualStudioCodeCredential, From cac192767f6d4ccc88ddafd0b96f709786eaa4a8 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Wed, 4 Aug 2021 01:29:01 -0700 Subject: [PATCH 05/18] application credential tests --- sdk/identity/identity/package.json | 1 + ...ertificate_on_the_environment_variables.js | 5 + ...ent_secret_on_the_environment_variables.js | 111 ++++++++ ..._usernamepassword_environment_variables.js | 111 ++++++++ ...ing_with_environment_client_certificate.js | 5 + ..._tracing_with_environment_client_secret.js | 111 ++++++++ ...acing_with_environment_usernamepassword.js | 111 ++++++++ ...icationcredential_authentication_failed.js | 76 ++++++ ...called_and_no_credential_was_configured.js | 5 + .../applicationCredential.browser.ts | 37 +++ .../src/credentials/applicationCredential.ts | 4 +- .../src/credentials/chainedTokenCredential.ts | 2 +- .../public/node/applicationCredential.spec.ts | 241 ++++++++++++++++++ 13 files changed, 817 insertions(+), 3 deletions(-) create mode 100644 sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_certificate_on_the_environment_variables.js create mode 100644 sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_secret_on_the_environment_variables.js create mode 100644 sdk/identity/identity/recordings/node/applicationcredential/recording_finds_and_uses_client_usernamepassword_environment_variables.js create mode 100644 sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_certificate.js create mode 100644 sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_secret.js create mode 100644 sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_usernamepassword.js create mode 100644 sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_authenticationerror_when_gettoken_is_called_and_applicationcredential_authentication_failed.js create mode 100644 sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_credentialunavailable_when_gettoken_is_called_and_no_credential_was_configured.js create mode 100644 sdk/identity/identity/src/credentials/applicationCredential.browser.ts create mode 100644 sdk/identity/identity/test/public/node/applicationCredential.spec.ts diff --git a/sdk/identity/identity/package.json b/sdk/identity/identity/package.json index b31b01eb623e..a0b7f94fc483 100644 --- a/sdk/identity/identity/package.json +++ b/sdk/identity/identity/package.json @@ -21,6 +21,7 @@ "./dist-esm/src/credentials/visualStudioCodeCredential.js": "./dist-esm/src/credentials/visualStudioCodeCredential.browser.js", "./dist-esm/src/credentials/usernamePasswordCredential.js": "./dist-esm/src/credentials/usernamePasswordCredential.browser.js", "./dist-esm/src/credentials/azurePowerShellCredential.js": "./dist-esm/src/credentials/azurePowerShellCredential.browser.js", + "./dist-esm/src/credentials/applicationCredentials.js": "./dist-esm/src/credentials/applicationCredentials.browser.js", "./dist-esm/src/util/authHostEnv.js": "./dist-esm/src/util/authHostEnv.browser.js", "./dist-esm/src/tokenCache/TokenCachePersistence.js": "./dist-esm/src/tokenCache/TokenCachePersistence.browser.js", "./dist-esm/src/extensions/consumer.js": "./dist-esm/src/extensions/consumer.browser.js", diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_certificate_on_the_environment_variables.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_certificate_on_the_environment_variables.js new file mode 100644 index 000000000000..54122f1c04f2 --- /dev/null +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_certificate_on_the_environment_variables.js @@ -0,0 +1,5 @@ +let nock = require('nock'); + +module.exports.hash = "770be7fa040679271c5ecc398a872004"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_secret_on_the_environment_variables.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_secret_on_the_environment_variables.js new file mode 100644 index 000000000000..f77d3400642e --- /dev/null +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_secret_on_the_environment_variables.js @@ -0,0 +1,111 @@ +let nock = require('nock'); + +module.exports.hash = "3a3f3ba54882469a6c079e922fe83278"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .get('/common/discovery/instance') + .query(true) + .reply(200, {"tenant_discovery_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}, [ + 'Cache-Control', + 'max-age=86400, private', + 'Content-Type', + 'application/json; charset=utf-8', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'Access-Control-Allow-Origin', + '*', + 'Access-Control-Allow-Methods', + 'GET, OPTIONS', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + '2ed2b765-f859-4906-9e34-7b9ee8152f02', + 'x-ms-ests-server', + '2.1.11898.12 - EUS ProdSlices', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:45 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:21:44 GMT', + 'Content-Length', + '980' +]); + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .get('/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration') + .reply(200, {"token_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}, [ + 'Cache-Control', + 'max-age=86400, private', + 'Content-Type', + 'application/json; charset=utf-8', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'Access-Control-Allow-Origin', + '*', + 'Access-Control-Allow-Methods', + 'GET, OPTIONS', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + 'e93b6981-435a-4bca-8244-68e1d9980201', + 'x-ms-ests-server', + '2.1.11898.12 - SCUS ProdSlices', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:45 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:21:44 GMT', + 'Content-Length', + '1753' +]); + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .post('/12345678-1234-1234-1234-123456789012/oauth2/v2.0/token', "client_id=azure_client_id&scope=https%3A%2F%2Fsanitized%2F&grant_type=client_credentials&x-client-SKU=msal.js.node&x-client-VER=1.2.0&x-client-OS=win32&x-client-CPU=x64&x-ms-lib-capability=retry-after, h429&x-client-current-telemetry=2|771,0|,&x-client-last-telemetry=2|0|||0,0&client-request-id=client-request-id&client_secret=azure_client_secret") + .reply(200, {"token_type":"Bearer","expires_in":86399,"ext_expires_in":86399,"access_token":"access_token"}, [ + 'Cache-Control', + 'no-store, no-cache', + 'Pragma', + 'no-cache', + 'Content-Type', + 'application/json; charset=utf-8', + 'Expires', + '-1', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + '5d399b4a-aad0-4d59-b3c5-c0b60683f900', + 'x-ms-ests-server', + '2.1.11898.12 - WUS2 ProdSlices', + 'x-ms-clitelem', + '1,0,0,,', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:45 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:21:45 GMT', + 'Content-Length', + '1315' +]); diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_finds_and_uses_client_usernamepassword_environment_variables.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_finds_and_uses_client_usernamepassword_environment_variables.js new file mode 100644 index 000000000000..a07e5d9176ad --- /dev/null +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_finds_and_uses_client_usernamepassword_environment_variables.js @@ -0,0 +1,111 @@ +let nock = require('nock'); + +module.exports.hash = "90ea55c253ab9555e53638d3d3b43858"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .get('/common/discovery/instance') + .query(true) + .reply(200, {"tenant_discovery_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}, [ + 'Cache-Control', + 'max-age=86400, private', + 'Content-Type', + 'application/json; charset=utf-8', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'Access-Control-Allow-Origin', + '*', + 'Access-Control-Allow-Methods', + 'GET, OPTIONS', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + '1fe2a56f-3cba-4d09-b578-5e6f8b394300', + 'x-ms-ests-server', + '2.1.11898.12 - NCUS ProdSlices', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:45 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:21:45 GMT', + 'Content-Length', + '980' +]); + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .get('/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration') + .reply(200, {"token_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0","request_uri_parameter_supported":false,"azure_azure_usernamenameinfo_endpoint":"https://graph.microsoft.com/oidc/azure_azure_usernamenameinfo","authorization_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_azure_azure_usernamenamename","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}, [ + 'Cache-Control', + 'max-age=86400, private', + 'Content-Type', + 'application/json; charset=utf-8', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'Access-Control-Allow-Origin', + '*', + 'Access-Control-Allow-Methods', + 'GET, OPTIONS', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + '22e757b3-2899-4102-9d93-2bc0947d0f01', + 'x-ms-ests-server', + '2.1.11898.12 - NCUS ProdSlices', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:45 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:21:45 GMT', + 'Content-Length', + '1753' +]); + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .post('/12345678-1234-1234-1234-123456789012/oauth2/v2.0/token', "client_id=azure_client_id&azure_azure_usernamenamename=azure_azure_usernamename&azure_azure_password=azure_azure_password&scope=scope%20openid%20profile%20offline_access&grant_type=azure_azure_password&client_info=1&x-client-SKU=msal.js.node&x-client-VER=1.2.0&x-client-OS=win32&x-client-CPU=x64&x-ms-lib-capability=retry-after, h429&x-client-current-telemetry=2|371,0|,&x-client-last-telemetry=2|0|||0,0&client-request-id=client-request-id") + .reply(400, {"error":"invalid_grant","error_description":"AADSTS50034: The azure_azure_usernamename account azure_azure_usernamename does not exist in the 12345678-1234-1234-1234-123456789012 directory. To sign into this application, the account must be added to the directory.\r\nTrace ID: 31eaf6eb-f2d8-4324-8d9f-0ddf70734101\r\nCorrelation ID: 2bd41f9f-0ec3-44e8-8ad0-f34262084004\r\nTimestamp: 2021-08-04 08:21:45Z","error_codes":[50034],"timestamp":"2021-08-04 08:21:45Z","trace_id":"31eaf6eb-f2d8-4324-8d9f-0ddf70734101","correlation_id":"2bd41f9f-0ec3-44e8-8ad0-f34262084004","error_uri":"https://login.microsoftonline.com/error?code=50034","suberror":"bad_token"}, [ + 'Cache-Control', + 'no-store, no-cache', + 'Pragma', + 'no-cache', + 'Content-Type', + 'application/json; charset=utf-8', + 'Expires', + '-1', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + '31eaf6eb-f2d8-4324-8d9f-0ddf70734101', + 'x-ms-ests-server', + '2.1.11898.12 - EUS ProdSlices', + 'x-ms-clitelem', + '1,50034,0,,', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:45 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:21:45 GMT', + 'Content-Length', + '619' +]); diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_certificate.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_certificate.js new file mode 100644 index 000000000000..5d3e9279fa79 --- /dev/null +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_certificate.js @@ -0,0 +1,5 @@ +let nock = require('nock'); + +module.exports.hash = "e854a1fc8b3484a8679124a3c20d5303"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_secret.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_secret.js new file mode 100644 index 000000000000..d566c4e36211 --- /dev/null +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_secret.js @@ -0,0 +1,111 @@ +let nock = require('nock'); + +module.exports.hash = "b5a4d41bd6e386f72f5a1e905188a949"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .get('/common/discovery/instance') + .query(true) + .reply(200, {"tenant_discovery_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}, [ + 'Cache-Control', + 'max-age=86400, private', + 'Content-Type', + 'application/json; charset=utf-8', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'Access-Control-Allow-Origin', + '*', + 'Access-Control-Allow-Methods', + 'GET, OPTIONS', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + 'a892443b-76f3-4070-8c5b-2702a1ea5c01', + 'x-ms-ests-server', + '2.1.11898.12 - EUS ProdSlices', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:46 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:21:45 GMT', + 'Content-Length', + '980' +]); + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .get('/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration') + .reply(200, {"token_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}, [ + 'Cache-Control', + 'max-age=86400, private', + 'Content-Type', + 'application/json; charset=utf-8', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'Access-Control-Allow-Origin', + '*', + 'Access-Control-Allow-Methods', + 'GET, OPTIONS', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + 'ffc5f067-3d30-4ee2-9e97-2cb8bd876a01', + 'x-ms-ests-server', + '2.1.11898.12 - EUS ProdSlices', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:46 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:21:45 GMT', + 'Content-Length', + '1753' +]); + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .post('/12345678-1234-1234-1234-123456789012/oauth2/v2.0/token', "client_id=azure_client_id&scope=https%3A%2F%2Fsanitized%2F&grant_type=client_credentials&x-client-SKU=msal.js.node&x-client-VER=1.2.0&x-client-OS=win32&x-client-CPU=x64&x-ms-lib-capability=retry-after, h429&x-client-current-telemetry=2|771,0|,&x-client-last-telemetry=2|0|||0,0&client-request-id=client-request-id&client_secret=azure_client_secret") + .reply(200, {"token_type":"Bearer","expires_in":86399,"ext_expires_in":86399,"access_token":"access_token"}, [ + 'Cache-Control', + 'no-store, no-cache', + 'Pragma', + 'no-cache', + 'Content-Type', + 'application/json; charset=utf-8', + 'Expires', + '-1', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + 'f928a215-a166-448c-adcc-58d552f51801', + 'x-ms-ests-server', + '2.1.11898.12 - NCUS ProdSlices', + 'x-ms-clitelem', + '1,0,0,,', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:46 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:21:45 GMT', + 'Content-Length', + '1315' +]); diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_usernamepassword.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_usernamepassword.js new file mode 100644 index 000000000000..05a63880aae8 --- /dev/null +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_usernamepassword.js @@ -0,0 +1,111 @@ +let nock = require('nock'); + +module.exports.hash = "b5a4d41bd6e386f72f5a1e905188a949"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .get('/common/discovery/instance') + .query(true) + .reply(200, {"tenant_discovery_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}, [ + 'Cache-Control', + 'max-age=86400, private', + 'Content-Type', + 'application/json; charset=utf-8', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'Access-Control-Allow-Origin', + '*', + 'Access-Control-Allow-Methods', + 'GET, OPTIONS', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + 'fe9f4fb9-40e4-4fde-ae5c-36e7e6a42402', + 'x-ms-ests-server', + '2.1.11898.12 - SCUS ProdSlices', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:25:42 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:25:41 GMT', + 'Content-Length', + '980' +]); + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .get('/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration') + .reply(200, {"token_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0","request_uri_parameter_supported":false,"azure_azure_usernamenameinfo_endpoint":"https://graph.microsoft.com/oidc/azure_azure_usernamenameinfo","authorization_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_azure_azure_usernamenamename","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}, [ + 'Cache-Control', + 'max-age=86400, private', + 'Content-Type', + 'application/json; charset=utf-8', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'Access-Control-Allow-Origin', + '*', + 'Access-Control-Allow-Methods', + 'GET, OPTIONS', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + '1db1aa08-cee3-4680-a515-efcc6de55201', + 'x-ms-ests-server', + '2.1.11898.12 - EUS ProdSlices', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:25:42 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:25:42 GMT', + 'Content-Length', + '1753' +]); + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .post('/12345678-1234-1234-1234-123456789012/oauth2/v2.0/token', "client_id=azure_client_id&azure_azure_usernamenamename=azure_azure_usernamename&azure_azure_password=azure_azure_password&scope=https%3A%2F%2Fsanitized%2F&grant_type=azure_azure_password&client_info=1&x-client-SKU=msal.js.node&x-client-VER=1.2.0&x-client-OS=win32&x-client-CPU=x64&x-ms-lib-capability=retry-after, h429&x-client-current-telemetry=2|371,0|,&x-client-last-telemetry=2|0|||0,0&client-request-id=client-request-id") + .reply(400, {"error":"invalid_grant","error_description":"AADSTS50034: The azure_azure_usernamename account azure_azure_usernamename does not exist in the 12345678-1234-1234-1234-123456789012 directory. To sign into this application, the account must be added to the directory.\r\nTrace ID: 1918afda-8c47-49a2-9b8c-c3d2cb694f01\r\nCorrelation ID: ca21231a-8476-4221-811b-96cb03410a76\r\nTimestamp: 2021-08-04 08:25:43Z","error_codes":[50034],"timestamp":"2021-08-04 08:25:43Z","trace_id":"1918afda-8c47-49a2-9b8c-c3d2cb694f01","correlation_id":"ca21231a-8476-4221-811b-96cb03410a76","error_uri":"https://login.microsoftonline.com/error?code=50034","suberror":"bad_token"}, [ + 'Cache-Control', + 'no-store, no-cache', + 'Pragma', + 'no-cache', + 'Content-Type', + 'application/json; charset=utf-8', + 'Expires', + '-1', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + '1918afda-8c47-49a2-9b8c-c3d2cb694f01', + 'x-ms-ests-server', + '2.1.11898.12 - EUS ProdSlices', + 'x-ms-clitelem', + '1,50034,0,,', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:25:43 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:25:42 GMT', + 'Content-Length', + '619' +]); diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_authenticationerror_when_gettoken_is_called_and_applicationcredential_authentication_failed.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_authenticationerror_when_gettoken_is_called_and_applicationcredential_authentication_failed.js new file mode 100644 index 000000000000..e3e56b20c183 --- /dev/null +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_authenticationerror_when_gettoken_is_called_and_applicationcredential_authentication_failed.js @@ -0,0 +1,76 @@ +let nock = require('nock'); + +module.exports.hash = "c0899b85b1280258c71e361d391d13d1"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .get('/common/discovery/instance') + .query(true) + .reply(200, {"12345678-1234-1234-1234-123456789012_discovery_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}, [ + 'Cache-Control', + 'max-age=86400, private', + 'Content-Type', + 'application/json; charset=utf-8', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'Access-Control-Allow-Origin', + '*', + 'Access-Control-Allow-Methods', + 'GET, OPTIONS', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + '2d9bbca3-545a-42ff-a091-e871ec8c9701', + 'x-ms-ests-server', + '2.1.11898.12 - WUS2 ProdSlices', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:23:16 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:23:16 GMT', + 'Content-Length', + '950' +]); + +nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) + .get('/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration') + .reply(400, {"error":"invalid_12345678-1234-1234-1234-123456789012","error_description":"AADSTS90002: Tenant '12345678-1234-1234-1234-123456789012' not found. This may happen if there are no active subscriptions for the 12345678-1234-1234-1234-123456789012. Check to make sure you have the correct 12345678-1234-1234-1234-123456789012 ID. Check with your subscription administrator.\r\nTrace ID: 81beda46-f15d-4e7d-b42b-71374dccc100\r\nCorrelation ID: c1b9b8e2-4ddf-484d-9e30-78fda6c79269\r\nTimestamp: 2021-08-04 08:23:17Z","error_codes":[90002],"timestamp":"2021-08-04 08:23:17Z","trace_id":"81beda46-f15d-4e7d-b42b-71374dccc100","correlation_id":"c1b9b8e2-4ddf-484d-9e30-78fda6c79269","error_uri":"https://login.microsoftonline.com/error?code=90002"}, [ + 'Cache-Control', + 'max-age=86400, private', + 'Content-Type', + 'application/json; charset=utf-8', + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains', + 'X-Content-Type-Options', + 'nosniff', + 'Access-Control-Allow-Origin', + '*', + 'Access-Control-Allow-Methods', + 'GET, OPTIONS', + 'P3P', + 'CP="DSP CUR OTPi IND OTRi ONL FIN"', + 'x-ms-request-id', + '81beda46-f15d-4e7d-b42b-71374dccc100', + 'x-ms-ests-server', + '2.1.11898.12 - EUS ProdSlices', + 'Set-Cookie', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:23:17 GMT; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', + 'Set-Cookie', + 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', + 'Set-Cookie', + 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', + 'Date', + 'Wed, 04 Aug 2021 08:23:16 GMT', + 'Content-Length', + '621' +]); diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_credentialunavailable_when_gettoken_is_called_and_no_credential_was_configured.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_credentialunavailable_when_gettoken_is_called_and_no_credential_was_configured.js new file mode 100644 index 000000000000..f62c6c5d6098 --- /dev/null +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_credentialunavailable_when_gettoken_is_called_and_no_credential_was_configured.js @@ -0,0 +1,5 @@ +let nock = require('nock'); + +module.exports.hash = "d97a485107090e3677e381ab546eead4"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/identity/identity/src/credentials/applicationCredential.browser.ts b/sdk/identity/identity/src/credentials/applicationCredential.browser.ts new file mode 100644 index 000000000000..15ec08e380ca --- /dev/null +++ b/sdk/identity/identity/src/credentials/applicationCredential.browser.ts @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { AccessToken } from "@azure/core-auth"; + +import { TokenCredentialOptions } from "../client/identityClient"; +import { credentialLogger, formatError } from "../util/logging"; +import { ChainedTokenCredential } from "./chainedTokenCredential"; + +const BrowserNotSupportedError = new Error( + "ApplicationCredential is not supported in the browser. Use InteractiveBrowserCredential instead." +); +const logger = credentialLogger("ApplicationCredential"); + +/** + * Provides a default {@link ChainedTokenCredential} configuration for + * applications that will be deployed to Azure. + * + * Only available in NodeJS. + */ +export class ApplicationCredential extends ChainedTokenCredential { + /** + * Creates an instance of the ApplicationCredential class. + * + * @param options - Options for configuring the client which makes the authentication request. + */ + constructor(_tokenCredentialOptions?: TokenCredentialOptions) { + super(); + logger.info(formatError("", BrowserNotSupportedError)); + throw BrowserNotSupportedError; + } + + public getToken(): Promise { + logger.getToken.info(formatError("", BrowserNotSupportedError)); + throw BrowserNotSupportedError; + } +} diff --git a/sdk/identity/identity/src/credentials/applicationCredential.ts b/sdk/identity/identity/src/credentials/applicationCredential.ts index 2026c7aae807..3685f66ee51d 100644 --- a/sdk/identity/identity/src/credentials/applicationCredential.ts +++ b/sdk/identity/identity/src/credentials/applicationCredential.ts @@ -12,7 +12,7 @@ import { ChainedTokenCredential } from "./chainedTokenCredential"; import { EnvironmentCredential } from "./environmentCredential"; import { CredentialPersistenceOptions } from "./credentialPersistenceOptions"; -import { DefaultManagedIdentityCredential } from "./defaultAzureCredential"; +import { ManagedIdentityCredential } from "./managedIdentityCredential"; /** * Provides options to configure the {@link ApplicationCredential} class. @@ -37,7 +37,7 @@ interface ApplicationCredentialConstructor { export const ApplicationCredentials: ApplicationCredentialConstructor[] = [ EnvironmentCredential, - DefaultManagedIdentityCredential + ManagedIdentityCredential ]; /** diff --git a/sdk/identity/identity/src/credentials/chainedTokenCredential.ts b/sdk/identity/identity/src/credentials/chainedTokenCredential.ts index d8ca5388ed23..b5ef62e2df1f 100644 --- a/sdk/identity/identity/src/credentials/chainedTokenCredential.ts +++ b/sdk/identity/identity/src/credentials/chainedTokenCredential.ts @@ -60,7 +60,7 @@ export class ChainedTokenCredential implements TokenCredential { let successfulCredentialName = ""; const errors = []; - const { span, updatedOptions } = createSpan("ChainedTokenCredential-getToken", options); + const { span, updatedOptions } = createSpan("ChainedTokenCredential.getToken", options); for (let i = 0; i < this._sources.length && token === null; i++) { try { diff --git a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts new file mode 100644 index 000000000000..9e5750ae476b --- /dev/null +++ b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts @@ -0,0 +1,241 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ + +import sinon from "sinon"; +import assert from "assert"; +import { isPlaybackMode } from "@azure/test-utils-recorder"; +import { + AuthenticationError, + CredentialUnavailableError, + ApplicationCredential, + UsernamePasswordCredential +} from "../../../src"; +import { MsalTestCleanup, msalNodeTestSetup, testTracing } from "../../msalTestUtils"; +import { assertRejects } from "../../authTestUtils"; +import { Context } from "mocha"; + +describe("ApplicationCredential", function() { + let cleanup: MsalTestCleanup; + const environmentVariableNames = [ + "AZURE_TENANT_ID", + "AZURE_CLIENT_ID", + "AZURE_CLIENT_SECRET", + "AZURE_CLIENT_CERTIFICATE_PATH", + "AZURE_USERNAME", + "AZURE_PASSWORD" + ]; + const cachedValues: Record = {}; + + beforeEach(function(this: Context) { + const setup = msalNodeTestSetup(this); + cleanup = setup.cleanup; + environmentVariableNames.forEach((name) => { + cachedValues[name] = process.env[name]; + delete process.env[name]; + }); + }); + afterEach(async function() { + await cleanup(); + environmentVariableNames.forEach((name) => { + process.env[name] = cachedValues[name]; + }); + }); + + const scope = "https://vault.azure.net/.default"; + + it("authenticates with a client secret on the environment variables", async function() { + // The following environment variables must be set for this to work. + // On TEST_MODE="playback", the recorder automatically fills them with stubbed values. + process.env.AZURE_TENANT_ID = cachedValues.AZURE_TENANT_ID; + process.env.AZURE_CLIENT_ID = cachedValues.AZURE_CLIENT_ID; + process.env.AZURE_CLIENT_SECRET = cachedValues.AZURE_CLIENT_SECRET; + + const credential = new ApplicationCredential(); + + const token = await credential.getToken(scope); + assert.ok(token?.token); + assert.ok(token?.expiresOnTimestamp! > Date.now()); + }); + + it.skip("authenticates with a client certificate on the environment variables", async function(this: Context) { + if (isPlaybackMode()) { + // MSAL creates a client assertion based on the certificate that I haven't been able to mock. + // This assertion could be provided as parameters, but we don't have that in the public API yet, + // and I'm trying to avoid having to generate one ourselves. + this.skip(); + } + + // The following environment variables must be set for this to work. + // On TEST_MODE="playback", the recorder automatically fills them with stubbed values. + process.env.AZURE_TENANT_ID = cachedValues.AZURE_TENANT_ID; + process.env.AZURE_CLIENT_ID = cachedValues.AZURE_CLIENT_ID; + process.env.AZURE_CLIENT_CERTIFICATE_PATH = cachedValues.AZURE_CLIENT_CERTIFICATE_PATH; + + const credential = new ApplicationCredential(); + + const token = await credential.getToken(scope); + assert.ok(token?.token); + assert.ok(token?.expiresOnTimestamp! > Date.now()); + }); + + it("finds and uses client username/password environment variables", async () => { + // The following environment variables must be set for this to work. + // On TEST_MODE="playback", the recorder automatically fills them with stubbed values. + process.env.AZURE_TENANT_ID = cachedValues.AZURE_TENANT_ID; + process.env.AZURE_CLIENT_ID = cachedValues.AZURE_CLIENT_ID; + process.env.AZURE_USERNAME = "user"; + process.env.AZURE_PASSWORD = "password"; + + const getTokenSpy = sinon.spy(UsernamePasswordCredential.prototype, "getToken"); + + try { + const credential = new ApplicationCredential(); + await credential.getToken("scope"); + } catch (e) { + // To avoid having to store passwords anywhere, this getToken request will fail. + // We will focus our test on making sure the underlying getToken was called. + } + + assert.equal( + getTokenSpy.callCount, + 1, + "UsernamePasswordCredential getToken should have been called" + ); + }); + + it( + "supports tracing with environment client secret", + testTracing({ + test: async (tracingOptions) => { + // The following environment variables must be set for this to work. + // On TEST_MODE="playback", the recorder automatically fills them with stubbed values. + process.env.AZURE_TENANT_ID = cachedValues.AZURE_TENANT_ID; + process.env.AZURE_CLIENT_ID = cachedValues.AZURE_CLIENT_ID; + process.env.AZURE_CLIENT_SECRET = cachedValues.AZURE_CLIENT_SECRET; + + const credential = new ApplicationCredential(); + + await credential.getToken(scope, { + tracingOptions + }); + }, + children: [ + { + name: "Azure.Identity.ChainedTokenCredential.getToken", + children: [ + { + name: "Azure.Identity.EnvironmentCredential.getToken", + children: [ + { + name: "Azure.Identity.ClientSecretCredential.getToken", + children: [] + } + ] + } + ] + } + ] + }) + ); + + it.skip("supports tracing with environment client certificate", async function(this: Context) { + if (isPlaybackMode()) { + // MSAL creates a client assertion based on the certificate that I haven't been able to mock. + // This assertion could be provided as parameters, but we don't have that in the public API yet, + // and I'm trying to avoid having to generate one ourselves. + this.skip(); + } + await testTracing({ + test: async (tracingOptions) => { + // The following environment variables must be set for this to work. + // On TEST_MODE="playback", the recorder automatically fills them with stubbed values. + process.env.AZURE_TENANT_ID = cachedValues.AZURE_TENANT_ID; + process.env.AZURE_CLIENT_ID = cachedValues.AZURE_CLIENT_ID; + process.env.AZURE_CLIENT_CERTIFICATE_PATH = cachedValues.AZURE_CLIENT_CERTIFICATE_PATH; + + const credential = new ApplicationCredential(); + + await credential.getToken(scope, { + tracingOptions + }); + }, + children: [ + { + name: "Azure.Identity.ChainedTokenCredential.getToken", + children: [ + { + name: "Azure.Identity.EnvironmentCredential.getToken", + children: [ + { + name: "Azure.Identity.ClientCertificateCredential.getToken", + children: [] + } + ] + } + ] + } + ] + })(); + }); + + it( + "supports tracing with environment username/password", + testTracing({ + test: async (tracingOptions) => { + // The following environment variables must be set for this to work. + // On TEST_MODE="playback", the recorder automatically fills them with stubbed values. + process.env.AZURE_TENANT_ID = cachedValues.AZURE_TENANT_ID; + process.env.AZURE_CLIENT_ID = cachedValues.AZURE_CLIENT_ID; + process.env.AZURE_USERNAME = "user"; + process.env.AZURE_PASSWORD = "password"; + const credential = new ApplicationCredential(); + + await credential.getToken(scope, { + tracingOptions + }); + }, + children: [ + { + name: "Azure.Identity.ChainedTokenCredential.getToken", + children: [ + { + name: "Azure.Identity.EnvironmentCredential.getToken", + children: [ + { + name: "Azure.Identity.UsernamePasswordCredential.getToken", + children: [] + } + ] + } + ] + } + ] + }) + ); + + it("throws an CredentialUnavailable when getToken is called and no credential was configured", async () => { + const credential = new ApplicationCredential(); + await assertRejects( + credential.getToken(scope), + (error: CredentialUnavailableError) => + error.message.indexOf("CredentialUnavailableError: EnvironmentCredential is unavailable.") > + -1 + ); + }); + + it("throws an AuthenticationError when getToken is called and ApplicationCredential authentication failed", async () => { + process.env.AZURE_TENANT_ID = "tenant"; + process.env.AZURE_CLIENT_ID = "client"; + process.env.AZURE_CLIENT_SECRET = "secret"; + + const credential = new ApplicationCredential(); + + await assertRejects( + credential.getToken(scope), + (error: AuthenticationError) => + error.errorResponse.error.indexOf("EnvironmentCredential authentication failed.") > -1 + ); + }); +}); From bf87ffe34a5c89d4bbbdf62f1f1086ff0d2a1143 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Wed, 4 Aug 2021 10:44:11 -0700 Subject: [PATCH 06/18] default management credential --- .../identity/src/credentials/applicationCredential.ts | 4 ++-- .../identity/src/credentials/defaultAzureCredential.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/identity/identity/src/credentials/applicationCredential.ts b/sdk/identity/identity/src/credentials/applicationCredential.ts index 3685f66ee51d..2026c7aae807 100644 --- a/sdk/identity/identity/src/credentials/applicationCredential.ts +++ b/sdk/identity/identity/src/credentials/applicationCredential.ts @@ -12,7 +12,7 @@ import { ChainedTokenCredential } from "./chainedTokenCredential"; import { EnvironmentCredential } from "./environmentCredential"; import { CredentialPersistenceOptions } from "./credentialPersistenceOptions"; -import { ManagedIdentityCredential } from "./managedIdentityCredential"; +import { DefaultManagedIdentityCredential } from "./defaultAzureCredential"; /** * Provides options to configure the {@link ApplicationCredential} class. @@ -37,7 +37,7 @@ interface ApplicationCredentialConstructor { export const ApplicationCredentials: ApplicationCredentialConstructor[] = [ EnvironmentCredential, - ManagedIdentityCredential + DefaultManagedIdentityCredential ]; /** diff --git a/sdk/identity/identity/src/credentials/defaultAzureCredential.ts b/sdk/identity/identity/src/credentials/defaultAzureCredential.ts index e67d383c6e0b..0d200e2e2b3b 100644 --- a/sdk/identity/identity/src/credentials/defaultAzureCredential.ts +++ b/sdk/identity/identity/src/credentials/defaultAzureCredential.ts @@ -44,7 +44,7 @@ interface DefaultCredentialConstructor { * A shim around ManagedIdentityCredential that adapts it to accept * `DefaultAzureCredentialOptions`. * - * @internal + * */ export class DefaultManagedIdentityCredential extends ManagedIdentityCredential { constructor(options?: DefaultAzureCredentialOptions) { From ea0a74e2eb10c45222579806695de794f63c60e5 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Wed, 4 Aug 2021 16:53:00 -0700 Subject: [PATCH 07/18] add all tests and recordings for public tests --- sdk/identity/identity/package.json | 2 +- ...ent_secret_on_the_environment_variables.js | 24 +-- ..._tracing_with_environment_client_secret.js | 22 +-- ...icationcredential_authentication_failed.js | 18 +-- ...called_and_no_credential_was_configured.js | 2 +- .../node/applicationCredential.spec.ts | 127 ++++++++++++++++ .../public/node/applicationCredential.spec.ts | 140 +----------------- 7 files changed, 166 insertions(+), 169 deletions(-) create mode 100644 sdk/identity/identity/test/internal/node/applicationCredential.spec.ts diff --git a/sdk/identity/identity/package.json b/sdk/identity/identity/package.json index a0b7f94fc483..310494712817 100644 --- a/sdk/identity/identity/package.json +++ b/sdk/identity/identity/package.json @@ -21,7 +21,7 @@ "./dist-esm/src/credentials/visualStudioCodeCredential.js": "./dist-esm/src/credentials/visualStudioCodeCredential.browser.js", "./dist-esm/src/credentials/usernamePasswordCredential.js": "./dist-esm/src/credentials/usernamePasswordCredential.browser.js", "./dist-esm/src/credentials/azurePowerShellCredential.js": "./dist-esm/src/credentials/azurePowerShellCredential.browser.js", - "./dist-esm/src/credentials/applicationCredentials.js": "./dist-esm/src/credentials/applicationCredentials.browser.js", + "./dist-esm/src/credentials/applicationCredential.js": "./dist-esm/src/credentials/applicationCredential.browser.js", "./dist-esm/src/util/authHostEnv.js": "./dist-esm/src/util/authHostEnv.browser.js", "./dist-esm/src/tokenCache/TokenCachePersistence.js": "./dist-esm/src/tokenCache/TokenCachePersistence.browser.js", "./dist-esm/src/extensions/consumer.js": "./dist-esm/src/extensions/consumer.browser.js", diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_secret_on_the_environment_variables.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_secret_on_the_environment_variables.js index f77d3400642e..0fdec0cd3de0 100644 --- a/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_secret_on_the_environment_variables.js +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_secret_on_the_environment_variables.js @@ -23,11 +23,11 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - '2ed2b765-f859-4906-9e34-7b9ee8152f02', + '03ae322b-b044-4a1c-bb4b-356792c20f01', 'x-ms-ests-server', - '2.1.11898.12 - EUS ProdSlices', + '2.1.11898.12 - NCUS ProdSlices', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:45 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:44 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', @@ -35,7 +35,7 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 08:21:44 GMT', + 'Wed, 04 Aug 2021 23:51:43 GMT', 'Content-Length', '980' ]); @@ -58,11 +58,11 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - 'e93b6981-435a-4bca-8244-68e1d9980201', + '9992900b-6b15-4fba-a29c-ff2c78781000', 'x-ms-ests-server', - '2.1.11898.12 - SCUS ProdSlices', + '2.1.11935.12 - WUS2 ProdSlices', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:45 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:44 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', @@ -70,7 +70,7 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 08:21:44 GMT', + 'Wed, 04 Aug 2021 23:51:43 GMT', 'Content-Length', '1753' ]); @@ -93,19 +93,19 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - '5d399b4a-aad0-4d59-b3c5-c0b60683f900', + '87031f9e-911b-4412-8e41-038050cc0600', 'x-ms-ests-server', - '2.1.11898.12 - WUS2 ProdSlices', + '2.1.11935.12 - NCUS ProdSlices', 'x-ms-clitelem', '1,0,0,,', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:45 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:44 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 08:21:45 GMT', + 'Wed, 04 Aug 2021 23:51:43 GMT', 'Content-Length', '1315' ]); diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_secret.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_secret.js index d566c4e36211..d73ed1f38a56 100644 --- a/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_secret.js +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_secret.js @@ -23,11 +23,11 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - 'a892443b-76f3-4070-8c5b-2702a1ea5c01', + 'd1b3b326-7705-40a6-bb97-a73aff866902', 'x-ms-ests-server', '2.1.11898.12 - EUS ProdSlices', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:46 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:44 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', @@ -35,7 +35,7 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 08:21:45 GMT', + 'Wed, 04 Aug 2021 23:51:43 GMT', 'Content-Length', '980' ]); @@ -58,11 +58,11 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - 'ffc5f067-3d30-4ee2-9e97-2cb8bd876a01', + '53bd86e2-56a4-43eb-bc48-a3243a4c0500', 'x-ms-ests-server', - '2.1.11898.12 - EUS ProdSlices', + '2.1.11935.12 - NCUS ProdSlices', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:46 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:44 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', @@ -70,7 +70,7 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 08:21:45 GMT', + 'Wed, 04 Aug 2021 23:51:43 GMT', 'Content-Length', '1753' ]); @@ -93,19 +93,19 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - 'f928a215-a166-448c-adcc-58d552f51801', + '6a6b1f25-7dc6-4684-bf38-252217330f00', 'x-ms-ests-server', - '2.1.11898.12 - NCUS ProdSlices', + '2.1.11935.12 - WUS2 ProdSlices', 'x-ms-clitelem', '1,0,0,,', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:46 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:44 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 08:21:45 GMT', + 'Wed, 04 Aug 2021 23:51:44 GMT', 'Content-Length', '1315' ]); diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_authenticationerror_when_gettoken_is_called_and_applicationcredential_authentication_failed.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_authenticationerror_when_gettoken_is_called_and_applicationcredential_authentication_failed.js index e3e56b20c183..de59badd5ba6 100644 --- a/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_authenticationerror_when_gettoken_is_called_and_applicationcredential_authentication_failed.js +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_authenticationerror_when_gettoken_is_called_and_applicationcredential_authentication_failed.js @@ -23,11 +23,11 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - '2d9bbca3-545a-42ff-a091-e871ec8c9701', + 'fd9ef937-a8ef-463e-9458-a42191d67a02', 'x-ms-ests-server', - '2.1.11898.12 - WUS2 ProdSlices', + '2.1.11898.12 - SCUS ProdSlices', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:23:16 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:51 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', @@ -35,14 +35,14 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 08:23:16 GMT', + 'Wed, 04 Aug 2021 23:51:50 GMT', 'Content-Length', '950' ]); nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) .get('/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration') - .reply(400, {"error":"invalid_12345678-1234-1234-1234-123456789012","error_description":"AADSTS90002: Tenant '12345678-1234-1234-1234-123456789012' not found. This may happen if there are no active subscriptions for the 12345678-1234-1234-1234-123456789012. Check to make sure you have the correct 12345678-1234-1234-1234-123456789012 ID. Check with your subscription administrator.\r\nTrace ID: 81beda46-f15d-4e7d-b42b-71374dccc100\r\nCorrelation ID: c1b9b8e2-4ddf-484d-9e30-78fda6c79269\r\nTimestamp: 2021-08-04 08:23:17Z","error_codes":[90002],"timestamp":"2021-08-04 08:23:17Z","trace_id":"81beda46-f15d-4e7d-b42b-71374dccc100","correlation_id":"c1b9b8e2-4ddf-484d-9e30-78fda6c79269","error_uri":"https://login.microsoftonline.com/error?code=90002"}, [ + .reply(400, {"error":"invalid_12345678-1234-1234-1234-123456789012","error_description":"AADSTS90002: Tenant '12345678-1234-1234-1234-123456789012' not found. This may happen if there are no active subscriptions for the 12345678-1234-1234-1234-123456789012. Check to make sure you have the correct 12345678-1234-1234-1234-123456789012 ID. Check with your subscription administrator.\r\nTrace ID: a598318a-476a-4c23-bccf-7d8bd8059002\r\nCorrelation ID: ae736832-b4ed-4875-a224-66e74deddd49\r\nTimestamp: 2021-08-04 23:51:51Z","error_codes":[90002],"timestamp":"2021-08-04 23:51:51Z","trace_id":"a598318a-476a-4c23-bccf-7d8bd8059002","correlation_id":"ae736832-b4ed-4875-a224-66e74deddd49","error_uri":"https://login.microsoftonline.com/error?code=90002"}, [ 'Cache-Control', 'max-age=86400, private', 'Content-Type', @@ -58,11 +58,11 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - '81beda46-f15d-4e7d-b42b-71374dccc100', + 'a598318a-476a-4c23-bccf-7d8bd8059002', 'x-ms-ests-server', - '2.1.11898.12 - EUS ProdSlices', + '2.1.11898.12 - SCUS ProdSlices', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:23:17 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:51 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', @@ -70,7 +70,7 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 08:23:16 GMT', + 'Wed, 04 Aug 2021 23:51:50 GMT', 'Content-Length', '621' ]); diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_credentialunavailable_when_gettoken_is_called_and_no_credential_was_configured.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_credentialunavailable_when_gettoken_is_called_and_no_credential_was_configured.js index f62c6c5d6098..05001dbb8c6d 100644 --- a/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_credentialunavailable_when_gettoken_is_called_and_no_credential_was_configured.js +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_credentialunavailable_when_gettoken_is_called_and_no_credential_was_configured.js @@ -1,5 +1,5 @@ let nock = require('nock'); -module.exports.hash = "d97a485107090e3677e381ab546eead4"; +module.exports.hash = "4e554d8e5855671556f71553d10c4e4c"; module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts b/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts new file mode 100644 index 000000000000..bfa8c0706c4f --- /dev/null +++ b/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import assert from "assert"; +import { RestError } from "@azure/core-http"; +import { + ManagedIdentityCredential, + AuthenticationError, + ApplicationCredential +} from "../../../src"; +import { MockAuthHttpClient, assertRejects } from "../../authTestUtils"; +import { OAuthErrorResponse } from "../../../src/client/errors"; +import Sinon from "sinon"; + +describe("ManagedIdentityCredential", function() { + let envCopy: string = ""; + let sandbox: Sinon.SinonSandbox; + + beforeEach(() => { + envCopy = JSON.stringify(process.env); + delete process.env.MSI_ENDPOINT; + delete process.env.MSI_SECRET; + sandbox = Sinon.createSandbox(); + }); + afterEach(() => { + const env = JSON.parse(envCopy); + process.env.MSI_ENDPOINT = env.MSI_ENDPOINT; + process.env.MSI_SECRET = env.MSI_SECRET; + sandbox.restore(); + }); + + it("returns error when no MSI is available", async function() { + process.env.AZURE_CLIENT_ID = "errclient"; + + const imdsError: RestError = new RestError("Request Timeout", "REQUEST_SEND_ERROR", 408); + const mockHttpClient = new MockAuthHttpClient({ + authResponse: [{ error: imdsError }] + }); + + const credential = new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID, { + ...mockHttpClient.tokenCredentialOptions + }); + await assertRejects( + credential.getToken("scopes"), + (error: AuthenticationError) => error.message.indexOf("No MSI credential available") > -1 + ); + }); + + it("an unexpected error bubbles all the way up", async function() { + process.env.AZURE_CLIENT_ID = "errclient"; + + const errResponse: OAuthErrorResponse = { + error: "ManagedIdentityCredential authentication failed.", + error_description: "" + }; + + const mockHttpClient = new MockAuthHttpClient({ + authResponse: [{ status: 200 }, { status: 500, parsedBody: errResponse }] + }); + + const credential = new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID, { + ...mockHttpClient.tokenCredentialOptions + }); + await assertRejects( + credential.getToken("scopes"), + (error: AuthenticationError) => error.message.indexOf(errResponse.error) > -1 + ); + }); + + it("returns expected error when the network was unreachable", async function() { + process.env.AZURE_CLIENT_ID = "errclient"; + + const netError: RestError = new RestError("Request Timeout", "ENETUNREACH", 408); + const mockHttpClient = new MockAuthHttpClient({ + authResponse: [{ status: 200 }, { error: netError }] + }); + + const credential = new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID, { + ...mockHttpClient.tokenCredentialOptions + }); + await assertRejects( + credential.getToken("scopes"), + (error: AuthenticationError) => error.message.indexOf("Network unreachable.") > -1 + ); + }); + + it("sends an authorization request correctly in an App Service environment", async () => { + // Trigger App Service behavior by setting environment variables + process.env.MSI_ENDPOINT = "https://endpoint"; + process.env.MSI_SECRET = "secret"; + + const mockHttpClient = new MockAuthHttpClient({ + authResponse: { + status: 200, + parsedBody: { + token: "token", + expires_on: "06/20/2019 02:57:58 +00:00" + } + } + }); + const credential = new ApplicationCredential({ ...mockHttpClient.tokenCredentialOptions }); + const token = await credential.getToken(["https://service/.default"]); + const authDetails = { token, requests: mockHttpClient.requests }; + + const authRequest = authDetails.requests[0]; + assert.ok(authRequest.query, "No query string parameters on request"); + if (authRequest.query) { + assert.equal(authRequest.method, "GET"); + assert.equal(authRequest.query["clientid"], "client"); + assert.equal(decodeURIComponent(authRequest.query["resource"]), "https://service"); + assert.ok( + authRequest.url.startsWith(process.env.MSI_ENDPOINT), + "URL does not start with expected host and path" + ); + assert.equal(authRequest.headers.get("secret"), process.env.MSI_SECRET); + assert.ok( + authRequest.url.indexOf(`api-version=2017-09-01`) > -1, + "URL does not have expected version" + ); + if (authDetails.token) { + assert.equal(authDetails.token.expiresOnTimestamp, 1560999478000); + } else { + assert.fail("No token was returned!"); + } + } + }); +}); diff --git a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts index 9e5750ae476b..21d20a750900 100644 --- a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts +++ b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts @@ -3,14 +3,11 @@ /* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ -import sinon from "sinon"; import assert from "assert"; -import { isPlaybackMode } from "@azure/test-utils-recorder"; import { AuthenticationError, CredentialUnavailableError, - ApplicationCredential, - UsernamePasswordCredential + ApplicationCredential } from "../../../src"; import { MsalTestCleanup, msalNodeTestSetup, testTracing } from "../../msalTestUtils"; import { assertRejects } from "../../authTestUtils"; @@ -18,14 +15,7 @@ import { Context } from "mocha"; describe("ApplicationCredential", function() { let cleanup: MsalTestCleanup; - const environmentVariableNames = [ - "AZURE_TENANT_ID", - "AZURE_CLIENT_ID", - "AZURE_CLIENT_SECRET", - "AZURE_CLIENT_CERTIFICATE_PATH", - "AZURE_USERNAME", - "AZURE_PASSWORD" - ]; + const environmentVariableNames = ["AZURE_TENANT_ID", "AZURE_CLIENT_ID", "AZURE_CLIENT_SECRET"]; const cachedValues: Record = {}; beforeEach(function(this: Context) { @@ -59,52 +49,6 @@ describe("ApplicationCredential", function() { assert.ok(token?.expiresOnTimestamp! > Date.now()); }); - it.skip("authenticates with a client certificate on the environment variables", async function(this: Context) { - if (isPlaybackMode()) { - // MSAL creates a client assertion based on the certificate that I haven't been able to mock. - // This assertion could be provided as parameters, but we don't have that in the public API yet, - // and I'm trying to avoid having to generate one ourselves. - this.skip(); - } - - // The following environment variables must be set for this to work. - // On TEST_MODE="playback", the recorder automatically fills them with stubbed values. - process.env.AZURE_TENANT_ID = cachedValues.AZURE_TENANT_ID; - process.env.AZURE_CLIENT_ID = cachedValues.AZURE_CLIENT_ID; - process.env.AZURE_CLIENT_CERTIFICATE_PATH = cachedValues.AZURE_CLIENT_CERTIFICATE_PATH; - - const credential = new ApplicationCredential(); - - const token = await credential.getToken(scope); - assert.ok(token?.token); - assert.ok(token?.expiresOnTimestamp! > Date.now()); - }); - - it("finds and uses client username/password environment variables", async () => { - // The following environment variables must be set for this to work. - // On TEST_MODE="playback", the recorder automatically fills them with stubbed values. - process.env.AZURE_TENANT_ID = cachedValues.AZURE_TENANT_ID; - process.env.AZURE_CLIENT_ID = cachedValues.AZURE_CLIENT_ID; - process.env.AZURE_USERNAME = "user"; - process.env.AZURE_PASSWORD = "password"; - - const getTokenSpy = sinon.spy(UsernamePasswordCredential.prototype, "getToken"); - - try { - const credential = new ApplicationCredential(); - await credential.getToken("scope"); - } catch (e) { - // To avoid having to store passwords anywhere, this getToken request will fail. - // We will focus our test on making sure the underlying getToken was called. - } - - assert.equal( - getTokenSpy.callCount, - 1, - "UsernamePasswordCredential getToken should have been called" - ); - }); - it( "supports tracing with environment client secret", testTracing({ @@ -140,88 +84,14 @@ describe("ApplicationCredential", function() { }) ); - it.skip("supports tracing with environment client certificate", async function(this: Context) { - if (isPlaybackMode()) { - // MSAL creates a client assertion based on the certificate that I haven't been able to mock. - // This assertion could be provided as parameters, but we don't have that in the public API yet, - // and I'm trying to avoid having to generate one ourselves. - this.skip(); - } - await testTracing({ - test: async (tracingOptions) => { - // The following environment variables must be set for this to work. - // On TEST_MODE="playback", the recorder automatically fills them with stubbed values. - process.env.AZURE_TENANT_ID = cachedValues.AZURE_TENANT_ID; - process.env.AZURE_CLIENT_ID = cachedValues.AZURE_CLIENT_ID; - process.env.AZURE_CLIENT_CERTIFICATE_PATH = cachedValues.AZURE_CLIENT_CERTIFICATE_PATH; - - const credential = new ApplicationCredential(); - - await credential.getToken(scope, { - tracingOptions - }); - }, - children: [ - { - name: "Azure.Identity.ChainedTokenCredential.getToken", - children: [ - { - name: "Azure.Identity.EnvironmentCredential.getToken", - children: [ - { - name: "Azure.Identity.ClientCertificateCredential.getToken", - children: [] - } - ] - } - ] - } - ] - })(); - }); - - it( - "supports tracing with environment username/password", - testTracing({ - test: async (tracingOptions) => { - // The following environment variables must be set for this to work. - // On TEST_MODE="playback", the recorder automatically fills them with stubbed values. - process.env.AZURE_TENANT_ID = cachedValues.AZURE_TENANT_ID; - process.env.AZURE_CLIENT_ID = cachedValues.AZURE_CLIENT_ID; - process.env.AZURE_USERNAME = "user"; - process.env.AZURE_PASSWORD = "password"; - const credential = new ApplicationCredential(); - - await credential.getToken(scope, { - tracingOptions - }); - }, - children: [ - { - name: "Azure.Identity.ChainedTokenCredential.getToken", - children: [ - { - name: "Azure.Identity.EnvironmentCredential.getToken", - children: [ - { - name: "Azure.Identity.UsernamePasswordCredential.getToken", - children: [] - } - ] - } - ] - } - ] - }) - ); - it("throws an CredentialUnavailable when getToken is called and no credential was configured", async () => { const credential = new ApplicationCredential(); await assertRejects( credential.getToken(scope), (error: CredentialUnavailableError) => - error.message.indexOf("CredentialUnavailableError: EnvironmentCredential is unavailable.") > - -1 + error.message.indexOf( + `CredentialUnavailableError: EnvironmentCredential is unavailable. No underlying credential could be used.\nCredentialUnavailableError: ManagedIdentityCredential is unavailable. Network unreachable.` + ) > -1 ); }); From d5bcd10bb8757c80e78fd85c2d30551e266ec1a0 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Wed, 4 Aug 2021 17:20:36 -0700 Subject: [PATCH 08/18] internal tests --- .../node/applicationCredential.spec.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts b/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts index bfa8c0706c4f..9c3b80e61ce2 100644 --- a/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts +++ b/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts @@ -3,16 +3,12 @@ import assert from "assert"; import { RestError } from "@azure/core-http"; -import { - ManagedIdentityCredential, - AuthenticationError, - ApplicationCredential -} from "../../../src"; +import { AuthenticationError, ApplicationCredential } from "../../../src"; import { MockAuthHttpClient, assertRejects } from "../../authTestUtils"; import { OAuthErrorResponse } from "../../../src/client/errors"; import Sinon from "sinon"; -describe("ManagedIdentityCredential", function() { +describe.skip("ApplicationCredential (internal)", function() { let envCopy: string = ""; let sandbox: Sinon.SinonSandbox; @@ -37,7 +33,7 @@ describe("ManagedIdentityCredential", function() { authResponse: [{ error: imdsError }] }); - const credential = new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID, { + const credential = new ApplicationCredential({ ...mockHttpClient.tokenCredentialOptions }); await assertRejects( @@ -50,7 +46,7 @@ describe("ManagedIdentityCredential", function() { process.env.AZURE_CLIENT_ID = "errclient"; const errResponse: OAuthErrorResponse = { - error: "ManagedIdentityCredential authentication failed.", + error: "ApplicationCredential authentication failed.", error_description: "" }; @@ -58,7 +54,7 @@ describe("ManagedIdentityCredential", function() { authResponse: [{ status: 200 }, { status: 500, parsedBody: errResponse }] }); - const credential = new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID, { + const credential = new ApplicationCredential({ ...mockHttpClient.tokenCredentialOptions }); await assertRejects( @@ -74,8 +70,8 @@ describe("ManagedIdentityCredential", function() { const mockHttpClient = new MockAuthHttpClient({ authResponse: [{ status: 200 }, { error: netError }] }); - - const credential = new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID, { + console.dir(mockHttpClient.tokenCredentialOptions); + const credential = new ApplicationCredential({ ...mockHttpClient.tokenCredentialOptions }); await assertRejects( From 6baa62a01e8d9d31c72dd1d72f3f019637a694e3 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Wed, 4 Aug 2021 20:22:57 -0700 Subject: [PATCH 09/18] debug tests --- sdk/identity/identity/test/authTestUtils.ts | 2 +- .../node/applicationCredential.spec.ts | 153 +++++++++--------- .../node/managedIdentityCredential.spec.ts | 2 +- .../public/node/applicationCredential.spec.ts | 16 +- 4 files changed, 86 insertions(+), 87 deletions(-) diff --git a/sdk/identity/identity/test/authTestUtils.ts b/sdk/identity/identity/test/authTestUtils.ts index 6a48ca4cd221..915f85498454 100644 --- a/sdk/identity/identity/test/authTestUtils.ts +++ b/sdk/identity/identity/test/authTestUtils.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { assert } from "chai"; +import assert from "assert"; import { AuthenticationError } from "../src"; import { DefaultAuthorityHost } from "../src/constants"; diff --git a/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts b/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts index 9c3b80e61ce2..029f1dcf73eb 100644 --- a/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts +++ b/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts @@ -2,82 +2,90 @@ // Licensed under the MIT license. import assert from "assert"; -import { RestError } from "@azure/core-http"; -import { AuthenticationError, ApplicationCredential } from "../../../src"; -import { MockAuthHttpClient, assertRejects } from "../../authTestUtils"; -import { OAuthErrorResponse } from "../../../src/client/errors"; -import Sinon from "sinon"; +import { RestError } from "@azure/core-rest-pipeline"; +import { ApplicationCredential } from "../../../src"; +import { prepareIdentityTests } from "../../httpRequests"; +import { + createResponse, + IdentityTestContext, + SendCredentialRequests +} from "../../httpRequestsCommon"; -describe.skip("ApplicationCredential (internal)", function() { +// interface AuthRequestDetails { +// requests: WebResource[]; +// token: AccessToken | null; +// } + +describe("ApplicationCredential (internal)", function() { let envCopy: string = ""; - let sandbox: Sinon.SinonSandbox; + let testContext: IdentityTestContext; + let sendCredentialRequests: SendCredentialRequests; - beforeEach(() => { + beforeEach(async () => { envCopy = JSON.stringify(process.env); delete process.env.MSI_ENDPOINT; delete process.env.MSI_SECRET; - sandbox = Sinon.createSandbox(); + testContext = await prepareIdentityTests({}); + sendCredentialRequests = testContext.sendCredentialRequests; }); - afterEach(() => { + afterEach(async () => { const env = JSON.parse(envCopy); process.env.MSI_ENDPOINT = env.MSI_ENDPOINT; process.env.MSI_SECRET = env.MSI_SECRET; - sandbox.restore(); + await testContext.restore(); }); it("returns error when no MSI is available", async function() { process.env.AZURE_CLIENT_ID = "errclient"; - const imdsError: RestError = new RestError("Request Timeout", "REQUEST_SEND_ERROR", 408); - const mockHttpClient = new MockAuthHttpClient({ - authResponse: [{ error: imdsError }] - }); - - const credential = new ApplicationCredential({ - ...mockHttpClient.tokenCredentialOptions + const { error } = await sendCredentialRequests({ + scopes: ["scopes"], + credential: new ApplicationCredential(), + insecureResponses: [ + { + error: new RestError("Request Timeout", { code: "REQUEST_SEND_ERROR", statusCode: 408 }) + } + ] }); - await assertRejects( - credential.getToken("scopes"), - (error: AuthenticationError) => error.message.indexOf("No MSI credential available") > -1 + assert.ok( + error!.message!.indexOf("No MSI credential available") > -1, + "Failed to match the expected error" ); }); it("an unexpected error bubbles all the way up", async function() { process.env.AZURE_CLIENT_ID = "errclient"; - const errResponse: OAuthErrorResponse = { - error: "ApplicationCredential authentication failed.", - error_description: "" - }; + const errorMessage = "ManagedIdentityCredential authentication failed."; - const mockHttpClient = new MockAuthHttpClient({ - authResponse: [{ status: 200 }, { status: 500, parsedBody: errResponse }] + const { error } = await sendCredentialRequests({ + scopes: ["scopes"], + credential: new ApplicationCredential(), + insecureResponses: [ + createResponse(200), // IMDS Endpoint ping + { error: new RestError(errorMessage, { statusCode: 500 }) } + ] }); - - const credential = new ApplicationCredential({ - ...mockHttpClient.tokenCredentialOptions - }); - await assertRejects( - credential.getToken("scopes"), - (error: AuthenticationError) => error.message.indexOf(errResponse.error) > -1 - ); + assert.ok(error?.message.startsWith(errorMessage)); }); it("returns expected error when the network was unreachable", async function() { process.env.AZURE_CLIENT_ID = "errclient"; - const netError: RestError = new RestError("Request Timeout", "ENETUNREACH", 408); - const mockHttpClient = new MockAuthHttpClient({ - authResponse: [{ status: 200 }, { error: netError }] + const netError: RestError = new RestError("Request Timeout", { + code: "ENETUNREACH", + statusCode: 408 }); - console.dir(mockHttpClient.tokenCredentialOptions); - const credential = new ApplicationCredential({ - ...mockHttpClient.tokenCredentialOptions + + const { error } = await sendCredentialRequests({ + scopes: ["scopes"], + credential: new ApplicationCredential(), + insecureResponses: [ + createResponse(200), // IMDS Endpoint ping + { error: netError } + ] }); - await assertRejects( - credential.getToken("scopes"), - (error: AuthenticationError) => error.message.indexOf("Network unreachable.") > -1 - ); + assert.ok(error!.message!.indexOf("Network unreachable.") > -1); }); it("sends an authorization request correctly in an App Service environment", async () => { @@ -85,39 +93,36 @@ describe.skip("ApplicationCredential (internal)", function() { process.env.MSI_ENDPOINT = "https://endpoint"; process.env.MSI_SECRET = "secret"; - const mockHttpClient = new MockAuthHttpClient({ - authResponse: { - status: 200, - parsedBody: { - token: "token", + const authDetails = await sendCredentialRequests({ + scopes: ["https://service/.default"], + credential: new ApplicationCredential(), + secureResponses: [ + createResponse(200, { + access_token: "token", expires_on: "06/20/2019 02:57:58 +00:00" - } - } + }) + ] }); - const credential = new ApplicationCredential({ ...mockHttpClient.tokenCredentialOptions }); - const token = await credential.getToken(["https://service/.default"]); - const authDetails = { token, requests: mockHttpClient.requests }; const authRequest = authDetails.requests[0]; - assert.ok(authRequest.query, "No query string parameters on request"); - if (authRequest.query) { - assert.equal(authRequest.method, "GET"); - assert.equal(authRequest.query["clientid"], "client"); - assert.equal(decodeURIComponent(authRequest.query["resource"]), "https://service"); - assert.ok( - authRequest.url.startsWith(process.env.MSI_ENDPOINT), - "URL does not start with expected host and path" - ); - assert.equal(authRequest.headers.get("secret"), process.env.MSI_SECRET); - assert.ok( - authRequest.url.indexOf(`api-version=2017-09-01`) > -1, - "URL does not have expected version" - ); - if (authDetails.token) { - assert.equal(authDetails.token.expiresOnTimestamp, 1560999478000); - } else { - assert.fail("No token was returned!"); - } + const query = new URLSearchParams(authRequest.url.split("?")[1]); + + assert.equal(authRequest.method, "GET"); + assert.equal(query.get("clientid"), "client"); + assert.equal(decodeURIComponent(query.get("resource")!), "https://service"); + assert.ok( + authRequest.url.startsWith(process.env.MSI_ENDPOINT), + "URL does not start with expected host and path" + ); + assert.equal(authRequest.headers.secret, process.env.MSI_SECRET); + assert.ok( + authRequest.url.indexOf(`api-version=2017-09-01`) > -1, + "URL does not have expected version" + ); + if (authDetails.result?.token) { + assert.equal(authDetails.result.expiresOnTimestamp, 1560999478000); + } else { + assert.fail("No token was returned!"); } }); }); diff --git a/sdk/identity/identity/test/internal/node/managedIdentityCredential.spec.ts b/sdk/identity/identity/test/internal/node/managedIdentityCredential.spec.ts index 3da16f6d3b9b..8a9c7b15cb65 100644 --- a/sdk/identity/identity/test/internal/node/managedIdentityCredential.spec.ts +++ b/sdk/identity/identity/test/internal/node/managedIdentityCredential.spec.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { assert } from "chai"; +import assert from "assert"; import { join } from "path"; import { tmpdir } from "os"; import { mkdtempSync, rmdirSync, unlinkSync, writeFileSync } from "fs"; diff --git a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts index 21d20a750900..d7ecc66e6078 100644 --- a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts +++ b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts @@ -4,13 +4,9 @@ /* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ import assert from "assert"; -import { - AuthenticationError, - CredentialUnavailableError, - ApplicationCredential -} from "../../../src"; +import { CredentialUnavailableError, ApplicationCredential } from "../../../src"; import { MsalTestCleanup, msalNodeTestSetup, testTracing } from "../../msalTestUtils"; -import { assertRejects } from "../../authTestUtils"; +import { getError } from "../../authTestUtils"; import { Context } from "mocha"; describe("ApplicationCredential", function() { @@ -102,10 +98,8 @@ describe("ApplicationCredential", function() { const credential = new ApplicationCredential(); - await assertRejects( - credential.getToken(scope), - (error: AuthenticationError) => - error.errorResponse.error.indexOf("EnvironmentCredential authentication failed.") > -1 - ); + const error = await getError(credential.getToken(scope)); + assert.equal(error.name, "AuthenticationError"); + assert.ok(error.message.indexOf("EnvironmentCredential authentication failed.") > -1); }); }); From af9f6073e1e8724587de1d61d070a775f356fcc0 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Thu, 5 Aug 2021 16:15:39 -0700 Subject: [PATCH 10/18] add all tests --- ...ertificate_on_the_environment_variables.js | 5 - ...ent_secret_on_the_environment_variables.js | 22 ++-- ..._usernamepassword_environment_variables.js | 111 ------------------ ...ing_with_environment_client_certificate.js | 5 - ..._tracing_with_environment_client_secret.js | 24 ++-- ...acing_with_environment_usernamepassword.js | 111 ------------------ ...icationcredential_authentication_failed.js | 18 +-- .../node/applicationCredential.spec.ts | 12 +- .../public/node/applicationCredential.spec.ts | 14 +-- .../public/node/environmentCredential.spec.ts | 2 +- 10 files changed, 46 insertions(+), 278 deletions(-) delete mode 100644 sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_certificate_on_the_environment_variables.js delete mode 100644 sdk/identity/identity/recordings/node/applicationcredential/recording_finds_and_uses_client_usernamepassword_environment_variables.js delete mode 100644 sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_certificate.js delete mode 100644 sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_usernamepassword.js diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_certificate_on_the_environment_variables.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_certificate_on_the_environment_variables.js deleted file mode 100644 index 54122f1c04f2..000000000000 --- a/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_certificate_on_the_environment_variables.js +++ /dev/null @@ -1,5 +0,0 @@ -let nock = require('nock'); - -module.exports.hash = "770be7fa040679271c5ecc398a872004"; - -module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_secret_on_the_environment_variables.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_secret_on_the_environment_variables.js index 0fdec0cd3de0..4a7df189d2dd 100644 --- a/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_secret_on_the_environment_variables.js +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_authenticates_with_a_client_secret_on_the_environment_variables.js @@ -23,11 +23,11 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - '03ae322b-b044-4a1c-bb4b-356792c20f01', + '54656735-48e1-4eb1-bfc3-42b302a05b00', 'x-ms-ests-server', - '2.1.11898.12 - NCUS ProdSlices', + '2.1.11935.12 - WUS2 ProdSlices', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:44 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Sat, 04-Sep-2021 23:14:12 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', @@ -35,7 +35,7 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 23:51:43 GMT', + 'Thu, 05 Aug 2021 23:14:12 GMT', 'Content-Length', '980' ]); @@ -58,11 +58,11 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - '9992900b-6b15-4fba-a29c-ff2c78781000', + '30d8ef8c-f820-4adc-96c8-853b32ff3800', 'x-ms-ests-server', '2.1.11935.12 - WUS2 ProdSlices', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:44 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Sat, 04-Sep-2021 23:14:12 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', @@ -70,7 +70,7 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 23:51:43 GMT', + 'Thu, 05 Aug 2021 23:14:12 GMT', 'Content-Length', '1753' ]); @@ -93,19 +93,19 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - '87031f9e-911b-4412-8e41-038050cc0600', + '5d25849e-e99b-4f2e-b3ec-7f4efa843b00', 'x-ms-ests-server', - '2.1.11935.12 - NCUS ProdSlices', + '2.1.11935.12 - SCUS ProdSlices', 'x-ms-clitelem', '1,0,0,,', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:44 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Sat, 04-Sep-2021 23:14:13 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 23:51:43 GMT', + 'Thu, 05 Aug 2021 23:14:12 GMT', 'Content-Length', '1315' ]); diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_finds_and_uses_client_usernamepassword_environment_variables.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_finds_and_uses_client_usernamepassword_environment_variables.js deleted file mode 100644 index a07e5d9176ad..000000000000 --- a/sdk/identity/identity/recordings/node/applicationcredential/recording_finds_and_uses_client_usernamepassword_environment_variables.js +++ /dev/null @@ -1,111 +0,0 @@ -let nock = require('nock'); - -module.exports.hash = "90ea55c253ab9555e53638d3d3b43858"; - -module.exports.testInfo = {"uniqueName":{},"newDate":{}} - -nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) - .get('/common/discovery/instance') - .query(true) - .reply(200, {"tenant_discovery_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}, [ - 'Cache-Control', - 'max-age=86400, private', - 'Content-Type', - 'application/json; charset=utf-8', - 'Strict-Transport-Security', - 'max-age=31536000; includeSubDomains', - 'X-Content-Type-Options', - 'nosniff', - 'Access-Control-Allow-Origin', - '*', - 'Access-Control-Allow-Methods', - 'GET, OPTIONS', - 'P3P', - 'CP="DSP CUR OTPi IND OTRi ONL FIN"', - 'x-ms-request-id', - '1fe2a56f-3cba-4d09-b578-5e6f8b394300', - 'x-ms-ests-server', - '2.1.11898.12 - NCUS ProdSlices', - 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:45 GMT; path=/; secure; HttpOnly; SameSite=None', - 'Set-Cookie', - 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', - 'Set-Cookie', - 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', - 'Set-Cookie', - 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', - 'Date', - 'Wed, 04 Aug 2021 08:21:45 GMT', - 'Content-Length', - '980' -]); - -nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) - .get('/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration') - .reply(200, {"token_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0","request_uri_parameter_supported":false,"azure_azure_usernamenameinfo_endpoint":"https://graph.microsoft.com/oidc/azure_azure_usernamenameinfo","authorization_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_azure_azure_usernamenamename","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}, [ - 'Cache-Control', - 'max-age=86400, private', - 'Content-Type', - 'application/json; charset=utf-8', - 'Strict-Transport-Security', - 'max-age=31536000; includeSubDomains', - 'X-Content-Type-Options', - 'nosniff', - 'Access-Control-Allow-Origin', - '*', - 'Access-Control-Allow-Methods', - 'GET, OPTIONS', - 'P3P', - 'CP="DSP CUR OTPi IND OTRi ONL FIN"', - 'x-ms-request-id', - '22e757b3-2899-4102-9d93-2bc0947d0f01', - 'x-ms-ests-server', - '2.1.11898.12 - NCUS ProdSlices', - 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:45 GMT; path=/; secure; HttpOnly; SameSite=None', - 'Set-Cookie', - 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', - 'Set-Cookie', - 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', - 'Set-Cookie', - 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', - 'Date', - 'Wed, 04 Aug 2021 08:21:45 GMT', - 'Content-Length', - '1753' -]); - -nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) - .post('/12345678-1234-1234-1234-123456789012/oauth2/v2.0/token', "client_id=azure_client_id&azure_azure_usernamenamename=azure_azure_usernamename&azure_azure_password=azure_azure_password&scope=scope%20openid%20profile%20offline_access&grant_type=azure_azure_password&client_info=1&x-client-SKU=msal.js.node&x-client-VER=1.2.0&x-client-OS=win32&x-client-CPU=x64&x-ms-lib-capability=retry-after, h429&x-client-current-telemetry=2|371,0|,&x-client-last-telemetry=2|0|||0,0&client-request-id=client-request-id") - .reply(400, {"error":"invalid_grant","error_description":"AADSTS50034: The azure_azure_usernamename account azure_azure_usernamename does not exist in the 12345678-1234-1234-1234-123456789012 directory. To sign into this application, the account must be added to the directory.\r\nTrace ID: 31eaf6eb-f2d8-4324-8d9f-0ddf70734101\r\nCorrelation ID: 2bd41f9f-0ec3-44e8-8ad0-f34262084004\r\nTimestamp: 2021-08-04 08:21:45Z","error_codes":[50034],"timestamp":"2021-08-04 08:21:45Z","trace_id":"31eaf6eb-f2d8-4324-8d9f-0ddf70734101","correlation_id":"2bd41f9f-0ec3-44e8-8ad0-f34262084004","error_uri":"https://login.microsoftonline.com/error?code=50034","suberror":"bad_token"}, [ - 'Cache-Control', - 'no-store, no-cache', - 'Pragma', - 'no-cache', - 'Content-Type', - 'application/json; charset=utf-8', - 'Expires', - '-1', - 'Strict-Transport-Security', - 'max-age=31536000; includeSubDomains', - 'X-Content-Type-Options', - 'nosniff', - 'P3P', - 'CP="DSP CUR OTPi IND OTRi ONL FIN"', - 'x-ms-request-id', - '31eaf6eb-f2d8-4324-8d9f-0ddf70734101', - 'x-ms-ests-server', - '2.1.11898.12 - EUS ProdSlices', - 'x-ms-clitelem', - '1,50034,0,,', - 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:21:45 GMT; path=/; secure; HttpOnly; SameSite=None', - 'Set-Cookie', - 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', - 'Set-Cookie', - 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', - 'Date', - 'Wed, 04 Aug 2021 08:21:45 GMT', - 'Content-Length', - '619' -]); diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_certificate.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_certificate.js deleted file mode 100644 index 5d3e9279fa79..000000000000 --- a/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_certificate.js +++ /dev/null @@ -1,5 +0,0 @@ -let nock = require('nock'); - -module.exports.hash = "e854a1fc8b3484a8679124a3c20d5303"; - -module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_secret.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_secret.js index d73ed1f38a56..f734a36f1443 100644 --- a/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_secret.js +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_client_secret.js @@ -23,11 +23,11 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - 'd1b3b326-7705-40a6-bb97-a73aff866902', + '8e585fff-4996-4728-83e0-518e7345de01', 'x-ms-ests-server', - '2.1.11898.12 - EUS ProdSlices', + '2.1.11898.12 - NCUS ProdSlices', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:44 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Sat, 04-Sep-2021 23:14:13 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', @@ -35,7 +35,7 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 23:51:43 GMT', + 'Thu, 05 Aug 2021 23:14:12 GMT', 'Content-Length', '980' ]); @@ -58,11 +58,11 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - '53bd86e2-56a4-43eb-bc48-a3243a4c0500', + '1bd469dd-c998-4c70-88ad-188983123a00', 'x-ms-ests-server', - '2.1.11935.12 - NCUS ProdSlices', + '2.1.11935.12 - EUS ProdSlices', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:44 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Sat, 04-Sep-2021 23:14:13 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', @@ -70,7 +70,7 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 23:51:43 GMT', + 'Thu, 05 Aug 2021 23:14:12 GMT', 'Content-Length', '1753' ]); @@ -93,19 +93,19 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - '6a6b1f25-7dc6-4684-bf38-252217330f00', + '20a1a05c-5822-474d-b862-ec1d8c8b3c00', 'x-ms-ests-server', - '2.1.11935.12 - WUS2 ProdSlices', + '2.1.11935.12 - EUS ProdSlices', 'x-ms-clitelem', '1,0,0,,', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:44 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Sat, 04-Sep-2021 23:14:13 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 23:51:44 GMT', + 'Thu, 05 Aug 2021 23:14:12 GMT', 'Content-Length', '1315' ]); diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_usernamepassword.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_usernamepassword.js deleted file mode 100644 index 05a63880aae8..000000000000 --- a/sdk/identity/identity/recordings/node/applicationcredential/recording_supports_tracing_with_environment_usernamepassword.js +++ /dev/null @@ -1,111 +0,0 @@ -let nock = require('nock'); - -module.exports.hash = "b5a4d41bd6e386f72f5a1e905188a949"; - -module.exports.testInfo = {"uniqueName":{},"newDate":{}} - -nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) - .get('/common/discovery/instance') - .query(true) - .reply(200, {"tenant_discovery_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}, [ - 'Cache-Control', - 'max-age=86400, private', - 'Content-Type', - 'application/json; charset=utf-8', - 'Strict-Transport-Security', - 'max-age=31536000; includeSubDomains', - 'X-Content-Type-Options', - 'nosniff', - 'Access-Control-Allow-Origin', - '*', - 'Access-Control-Allow-Methods', - 'GET, OPTIONS', - 'P3P', - 'CP="DSP CUR OTPi IND OTRi ONL FIN"', - 'x-ms-request-id', - 'fe9f4fb9-40e4-4fde-ae5c-36e7e6a42402', - 'x-ms-ests-server', - '2.1.11898.12 - SCUS ProdSlices', - 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:25:42 GMT; path=/; secure; HttpOnly; SameSite=None', - 'Set-Cookie', - 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', - 'Set-Cookie', - 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', - 'Set-Cookie', - 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', - 'Date', - 'Wed, 04 Aug 2021 08:25:41 GMT', - 'Content-Length', - '980' -]); - -nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) - .get('/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration') - .reply(200, {"token_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/v2.0","request_uri_parameter_supported":false,"azure_azure_usernamenameinfo_endpoint":"https://graph.microsoft.com/oidc/azure_azure_usernamenameinfo","authorization_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_azure_azure_usernamenamename","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/12345678-1234-1234-1234-123456789012/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}, [ - 'Cache-Control', - 'max-age=86400, private', - 'Content-Type', - 'application/json; charset=utf-8', - 'Strict-Transport-Security', - 'max-age=31536000; includeSubDomains', - 'X-Content-Type-Options', - 'nosniff', - 'Access-Control-Allow-Origin', - '*', - 'Access-Control-Allow-Methods', - 'GET, OPTIONS', - 'P3P', - 'CP="DSP CUR OTPi IND OTRi ONL FIN"', - 'x-ms-request-id', - '1db1aa08-cee3-4680-a515-efcc6de55201', - 'x-ms-ests-server', - '2.1.11898.12 - EUS ProdSlices', - 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:25:42 GMT; path=/; secure; HttpOnly; SameSite=None', - 'Set-Cookie', - 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', - 'Set-Cookie', - 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', - 'Set-Cookie', - 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', - 'Date', - 'Wed, 04 Aug 2021 08:25:42 GMT', - 'Content-Length', - '1753' -]); - -nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) - .post('/12345678-1234-1234-1234-123456789012/oauth2/v2.0/token', "client_id=azure_client_id&azure_azure_usernamenamename=azure_azure_usernamename&azure_azure_password=azure_azure_password&scope=https%3A%2F%2Fsanitized%2F&grant_type=azure_azure_password&client_info=1&x-client-SKU=msal.js.node&x-client-VER=1.2.0&x-client-OS=win32&x-client-CPU=x64&x-ms-lib-capability=retry-after, h429&x-client-current-telemetry=2|371,0|,&x-client-last-telemetry=2|0|||0,0&client-request-id=client-request-id") - .reply(400, {"error":"invalid_grant","error_description":"AADSTS50034: The azure_azure_usernamename account azure_azure_usernamename does not exist in the 12345678-1234-1234-1234-123456789012 directory. To sign into this application, the account must be added to the directory.\r\nTrace ID: 1918afda-8c47-49a2-9b8c-c3d2cb694f01\r\nCorrelation ID: ca21231a-8476-4221-811b-96cb03410a76\r\nTimestamp: 2021-08-04 08:25:43Z","error_codes":[50034],"timestamp":"2021-08-04 08:25:43Z","trace_id":"1918afda-8c47-49a2-9b8c-c3d2cb694f01","correlation_id":"ca21231a-8476-4221-811b-96cb03410a76","error_uri":"https://login.microsoftonline.com/error?code=50034","suberror":"bad_token"}, [ - 'Cache-Control', - 'no-store, no-cache', - 'Pragma', - 'no-cache', - 'Content-Type', - 'application/json; charset=utf-8', - 'Expires', - '-1', - 'Strict-Transport-Security', - 'max-age=31536000; includeSubDomains', - 'X-Content-Type-Options', - 'nosniff', - 'P3P', - 'CP="DSP CUR OTPi IND OTRi ONL FIN"', - 'x-ms-request-id', - '1918afda-8c47-49a2-9b8c-c3d2cb694f01', - 'x-ms-ests-server', - '2.1.11898.12 - EUS ProdSlices', - 'x-ms-clitelem', - '1,50034,0,,', - 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 08:25:43 GMT; path=/; secure; HttpOnly; SameSite=None', - 'Set-Cookie', - 'x-ms-gateway-slice=estsfd; path=/; secure; samesite=none; httponly', - 'Set-Cookie', - 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', - 'Date', - 'Wed, 04 Aug 2021 08:25:42 GMT', - 'Content-Length', - '619' -]); diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_authenticationerror_when_gettoken_is_called_and_applicationcredential_authentication_failed.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_authenticationerror_when_gettoken_is_called_and_applicationcredential_authentication_failed.js index de59badd5ba6..dd0ab0f7ca5b 100644 --- a/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_authenticationerror_when_gettoken_is_called_and_applicationcredential_authentication_failed.js +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_authenticationerror_when_gettoken_is_called_and_applicationcredential_authentication_failed.js @@ -23,11 +23,11 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - 'fd9ef937-a8ef-463e-9458-a42191d67a02', + '87378bfa-4cc9-4279-998f-d187ff277201', 'x-ms-ests-server', - '2.1.11898.12 - SCUS ProdSlices', + '2.1.11898.12 - EUS ProdSlices', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:51 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Sat, 04-Sep-2021 23:14:13 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', @@ -35,14 +35,14 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 23:51:50 GMT', + 'Thu, 05 Aug 2021 23:14:13 GMT', 'Content-Length', '950' ]); nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) .get('/12345678-1234-1234-1234-123456789012/v2.0/.well-known/openid-configuration') - .reply(400, {"error":"invalid_12345678-1234-1234-1234-123456789012","error_description":"AADSTS90002: Tenant '12345678-1234-1234-1234-123456789012' not found. This may happen if there are no active subscriptions for the 12345678-1234-1234-1234-123456789012. Check to make sure you have the correct 12345678-1234-1234-1234-123456789012 ID. Check with your subscription administrator.\r\nTrace ID: a598318a-476a-4c23-bccf-7d8bd8059002\r\nCorrelation ID: ae736832-b4ed-4875-a224-66e74deddd49\r\nTimestamp: 2021-08-04 23:51:51Z","error_codes":[90002],"timestamp":"2021-08-04 23:51:51Z","trace_id":"a598318a-476a-4c23-bccf-7d8bd8059002","correlation_id":"ae736832-b4ed-4875-a224-66e74deddd49","error_uri":"https://login.microsoftonline.com/error?code=90002"}, [ + .reply(400, {"error":"invalid_12345678-1234-1234-1234-123456789012","error_description":"AADSTS90002: Tenant '12345678-1234-1234-1234-123456789012' not found. This may happen if there are no active subscriptions for the 12345678-1234-1234-1234-123456789012. Check to make sure you have the correct 12345678-1234-1234-1234-123456789012 ID. Check with your subscription administrator.\r\nTrace ID: c95ed377-3195-434d-8cac-0f5460a11f02\r\nCorrelation ID: 5bf6f73d-9031-4e3f-b44e-7b7d1ebe9864\r\nTimestamp: 2021-08-05 23:14:13Z","error_codes":[90002],"timestamp":"2021-08-05 23:14:13Z","trace_id":"c95ed377-3195-434d-8cac-0f5460a11f02","correlation_id":"5bf6f73d-9031-4e3f-b44e-7b7d1ebe9864","error_uri":"https://login.microsoftonline.com/error?code=90002"}, [ 'Cache-Control', 'max-age=86400, private', 'Content-Type', @@ -58,11 +58,11 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'P3P', 'CP="DSP CUR OTPi IND OTRi ONL FIN"', 'x-ms-request-id', - 'a598318a-476a-4c23-bccf-7d8bd8059002', + 'c95ed377-3195-434d-8cac-0f5460a11f02', 'x-ms-ests-server', - '2.1.11898.12 - SCUS ProdSlices', + '2.1.11898.12 - NCUS ProdSlices', 'Set-Cookie', - 'fpc=fpc;; expires=Fri, 03-Sep-2021 23:51:51 GMT; path=/; secure; HttpOnly; SameSite=None', + 'fpc=fpc;; expires=Sat, 04-Sep-2021 23:14:13 GMT; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', 'esctx=esctx; domain=.login.microsoftonline.com; path=/; secure; HttpOnly; SameSite=None', 'Set-Cookie', @@ -70,7 +70,7 @@ nock('https://login.microsoftonline.com:443', {"encodedQueryParams":true}) 'Set-Cookie', 'stsservicecookie=estsfd; path=/; secure; samesite=none; httponly', 'Date', - 'Wed, 04 Aug 2021 23:51:50 GMT', + 'Thu, 05 Aug 2021 23:14:13 GMT', 'Content-Length', '621' ]); diff --git a/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts b/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts index 029f1dcf73eb..e9cfd4972e58 100644 --- a/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts +++ b/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts @@ -11,12 +11,7 @@ import { SendCredentialRequests } from "../../httpRequestsCommon"; -// interface AuthRequestDetails { -// requests: WebResource[]; -// token: AccessToken | null; -// } - -describe("ApplicationCredential (internal)", function() { +describe("ApplicationCredential testing Managed Identity (internal)", function() { let envCopy: string = ""; let testContext: IdentityTestContext; let sendCredentialRequests: SendCredentialRequests; @@ -25,6 +20,8 @@ describe("ApplicationCredential (internal)", function() { envCopy = JSON.stringify(process.env); delete process.env.MSI_ENDPOINT; delete process.env.MSI_SECRET; + delete process.env.AZURE_CLIENT_SECRET; + delete process.env.AZURE_TENANT_ID; testContext = await prepareIdentityTests({}); sendCredentialRequests = testContext.sendCredentialRequests; }); @@ -32,6 +29,8 @@ describe("ApplicationCredential (internal)", function() { const env = JSON.parse(envCopy); process.env.MSI_ENDPOINT = env.MSI_ENDPOINT; process.env.MSI_SECRET = env.MSI_SECRET; + process.env.AZURE_CLIENT_SECRET = env.AZURE_CLIENT_SECRET; + process.env.AZURE_TENANT_ID = env.AZURE_TENANT_ID; await testContext.restore(); }); @@ -90,6 +89,7 @@ describe("ApplicationCredential (internal)", function() { it("sends an authorization request correctly in an App Service environment", async () => { // Trigger App Service behavior by setting environment variables + process.env.AZURE_CLIENT_ID = "client"; process.env.MSI_ENDPOINT = "https://endpoint"; process.env.MSI_SECRET = "secret"; diff --git a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts index d7ecc66e6078..4229b28f866d 100644 --- a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts +++ b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts @@ -4,7 +4,7 @@ /* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ import assert from "assert"; -import { CredentialUnavailableError, ApplicationCredential } from "../../../src"; +import { ApplicationCredential } from "../../../src"; import { MsalTestCleanup, msalNodeTestSetup, testTracing } from "../../msalTestUtils"; import { getError } from "../../authTestUtils"; import { Context } from "mocha"; @@ -82,12 +82,12 @@ describe("ApplicationCredential", function() { it("throws an CredentialUnavailable when getToken is called and no credential was configured", async () => { const credential = new ApplicationCredential(); - await assertRejects( - credential.getToken(scope), - (error: CredentialUnavailableError) => - error.message.indexOf( - `CredentialUnavailableError: EnvironmentCredential is unavailable. No underlying credential could be used.\nCredentialUnavailableError: ManagedIdentityCredential is unavailable. Network unreachable.` - ) > -1 + const error = await getError(credential.getToken(scope)); + assert.equal(error.name, "CredentialUnavailableError"); + assert.ok( + error.message.indexOf( + `CredentialUnavailableError: EnvironmentCredential is unavailable. No underlying credential could be used.\nCredentialUnavailableError: ManagedIdentityCredential is unavailable. Network unreachable.` + ) > -1 ); }); diff --git a/sdk/identity/identity/test/public/node/environmentCredential.spec.ts b/sdk/identity/identity/test/public/node/environmentCredential.spec.ts index 3450bd9dddbd..08a775dac020 100644 --- a/sdk/identity/identity/test/public/node/environmentCredential.spec.ts +++ b/sdk/identity/identity/test/public/node/environmentCredential.spec.ts @@ -4,7 +4,7 @@ /* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ import sinon from "sinon"; -import { assert } from "chai"; +import assert from "assert"; import { isPlaybackMode } from "@azure/test-utils-recorder"; import { EnvironmentCredential, UsernamePasswordCredential } from "../../../src"; import { MsalTestCleanup, msalNodeTestSetup, testTracing } from "../../msalTestUtils"; From 0e68e582d219bdebae55e1bd5f7b39852791e1db Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Fri, 6 Aug 2021 16:10:08 -0700 Subject: [PATCH 11/18] update test and recording for that test --- ...gettoken_is_called_and_no_credential_was_configured.js} | 2 +- .../test/public/node/applicationCredential.spec.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) rename sdk/identity/identity/recordings/node/applicationcredential/{recording_throws_an_credentialunavailable_when_gettoken_is_called_and_no_credential_was_configured.js => recording_throws_an_aggregateauthenticationerror_when_gettoken_is_called_and_no_credential_was_configured.js} (60%) diff --git a/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_credentialunavailable_when_gettoken_is_called_and_no_credential_was_configured.js b/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_aggregateauthenticationerror_when_gettoken_is_called_and_no_credential_was_configured.js similarity index 60% rename from sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_credentialunavailable_when_gettoken_is_called_and_no_credential_was_configured.js rename to sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_aggregateauthenticationerror_when_gettoken_is_called_and_no_credential_was_configured.js index 05001dbb8c6d..d5acef5667c8 100644 --- a/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_credentialunavailable_when_gettoken_is_called_and_no_credential_was_configured.js +++ b/sdk/identity/identity/recordings/node/applicationcredential/recording_throws_an_aggregateauthenticationerror_when_gettoken_is_called_and_no_credential_was_configured.js @@ -1,5 +1,5 @@ let nock = require('nock'); -module.exports.hash = "4e554d8e5855671556f71553d10c4e4c"; +module.exports.hash = "f27429ae778247301f35d4567e0e1af5"; module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts index 4229b28f866d..a4c34d990d28 100644 --- a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts +++ b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts @@ -80,13 +80,14 @@ describe("ApplicationCredential", function() { }) ); - it("throws an CredentialUnavailable when getToken is called and no credential was configured", async () => { + it("throws an AggregateAuthenticationError when getToken is called and no credential was configured", async () => { const credential = new ApplicationCredential(); const error = await getError(credential.getToken(scope)); - assert.equal(error.name, "CredentialUnavailableError"); + assert.equal(error.name, "AggregateAuthenticationError"); + console.log(`${error.message}`); assert.ok( error.message.indexOf( - `CredentialUnavailableError: EnvironmentCredential is unavailable. No underlying credential could be used.\nCredentialUnavailableError: ManagedIdentityCredential is unavailable. Network unreachable.` + `CredentialUnavailableError: EnvironmentCredential is unavailable. No underlying credential could be used.\nCredentialUnavailableError: ManagedIdentityCredential authentication failed. Message ManagedIdentityCredential - No MSI credential available` ) > -1 ); }); From 113749939bb902bb0e0721fe3c0d8baa38a9b6dd Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Fri, 6 Aug 2021 16:41:43 -0700 Subject: [PATCH 12/18] remove assert refs --- sdk/identity/identity/test/authTestUtils.ts | 2 +- .../identity/test/internal/node/applicationCredential.spec.ts | 2 +- .../test/internal/node/managedIdentityCredential.spec.ts | 2 +- .../identity/test/public/node/applicationCredential.spec.ts | 2 +- .../identity/test/public/node/environmentCredential.spec.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sdk/identity/identity/test/authTestUtils.ts b/sdk/identity/identity/test/authTestUtils.ts index 915f85498454..6a48ca4cd221 100644 --- a/sdk/identity/identity/test/authTestUtils.ts +++ b/sdk/identity/identity/test/authTestUtils.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import assert from "assert"; +import { assert } from "chai"; import { AuthenticationError } from "../src"; import { DefaultAuthorityHost } from "../src/constants"; diff --git a/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts b/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts index e9cfd4972e58..9059c4d2f512 100644 --- a/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts +++ b/sdk/identity/identity/test/internal/node/applicationCredential.spec.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import assert from "assert"; +import { assert } from "chai"; import { RestError } from "@azure/core-rest-pipeline"; import { ApplicationCredential } from "../../../src"; import { prepareIdentityTests } from "../../httpRequests"; diff --git a/sdk/identity/identity/test/internal/node/managedIdentityCredential.spec.ts b/sdk/identity/identity/test/internal/node/managedIdentityCredential.spec.ts index 8a9c7b15cb65..3da16f6d3b9b 100644 --- a/sdk/identity/identity/test/internal/node/managedIdentityCredential.spec.ts +++ b/sdk/identity/identity/test/internal/node/managedIdentityCredential.spec.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import assert from "assert"; +import { assert } from "chai"; import { join } from "path"; import { tmpdir } from "os"; import { mkdtempSync, rmdirSync, unlinkSync, writeFileSync } from "fs"; diff --git a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts index a4c34d990d28..b919ebca0636 100644 --- a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts +++ b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts @@ -3,7 +3,7 @@ /* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ -import assert from "assert"; +import { assert } from "chai"; import { ApplicationCredential } from "../../../src"; import { MsalTestCleanup, msalNodeTestSetup, testTracing } from "../../msalTestUtils"; import { getError } from "../../authTestUtils"; diff --git a/sdk/identity/identity/test/public/node/environmentCredential.spec.ts b/sdk/identity/identity/test/public/node/environmentCredential.spec.ts index 08a775dac020..3450bd9dddbd 100644 --- a/sdk/identity/identity/test/public/node/environmentCredential.spec.ts +++ b/sdk/identity/identity/test/public/node/environmentCredential.spec.ts @@ -4,7 +4,7 @@ /* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ import sinon from "sinon"; -import assert from "assert"; +import { assert } from "chai"; import { isPlaybackMode } from "@azure/test-utils-recorder"; import { EnvironmentCredential, UsernamePasswordCredential } from "../../../src"; import { MsalTestCleanup, msalNodeTestSetup, testTracing } from "../../msalTestUtils"; From 04e4676747214d27842567a0d27d7f268d1ee1b3 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Fri, 6 Aug 2021 16:49:14 -0700 Subject: [PATCH 13/18] fix lint --- .../identity/test/public/node/applicationCredential.spec.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts index b919ebca0636..f4dc1f20f02b 100644 --- a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts +++ b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ - import { assert } from "chai"; import { ApplicationCredential } from "../../../src"; import { MsalTestCleanup, msalNodeTestSetup, testTracing } from "../../msalTestUtils"; @@ -42,7 +40,7 @@ describe("ApplicationCredential", function() { const token = await credential.getToken(scope); assert.ok(token?.token); - assert.ok(token?.expiresOnTimestamp! > Date.now()); + assert.ok(token?.expiresOnTimestamp > Date.now()); }); it( From 599b288f96cc46719b2a483a34b34a428ca97596 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Fri, 6 Aug 2021 16:50:19 -0700 Subject: [PATCH 14/18] remove unnecessary spacing --- sdk/identity/identity/src/credentials/applicationCredential.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/sdk/identity/identity/src/credentials/applicationCredential.ts b/sdk/identity/identity/src/credentials/applicationCredential.ts index 2026c7aae807..1f36a3d2c17a 100644 --- a/sdk/identity/identity/src/credentials/applicationCredential.ts +++ b/sdk/identity/identity/src/credentials/applicationCredential.ts @@ -5,11 +5,8 @@ // Licensed under the MIT license. import { TokenCredential } from "@azure/core-auth"; - import { TokenCredentialOptions } from "../client/identityClient"; - import { ChainedTokenCredential } from "./chainedTokenCredential"; - import { EnvironmentCredential } from "./environmentCredential"; import { CredentialPersistenceOptions } from "./credentialPersistenceOptions"; import { DefaultManagedIdentityCredential } from "./defaultAzureCredential"; From f11b550486e0907621f77da143e930ca29609a34 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Fri, 6 Aug 2021 16:53:54 -0700 Subject: [PATCH 15/18] fix tracing and add internal to defaultMangaedIdentityCred --- sdk/identity/identity/src/credentials/chainedTokenCredential.ts | 2 +- sdk/identity/identity/src/credentials/defaultAzureCredential.ts | 2 +- .../identity/test/public/node/applicationCredential.spec.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/identity/identity/src/credentials/chainedTokenCredential.ts b/sdk/identity/identity/src/credentials/chainedTokenCredential.ts index b5ef62e2df1f..d8ca5388ed23 100644 --- a/sdk/identity/identity/src/credentials/chainedTokenCredential.ts +++ b/sdk/identity/identity/src/credentials/chainedTokenCredential.ts @@ -60,7 +60,7 @@ export class ChainedTokenCredential implements TokenCredential { let successfulCredentialName = ""; const errors = []; - const { span, updatedOptions } = createSpan("ChainedTokenCredential.getToken", options); + const { span, updatedOptions } = createSpan("ChainedTokenCredential-getToken", options); for (let i = 0; i < this._sources.length && token === null; i++) { try { diff --git a/sdk/identity/identity/src/credentials/defaultAzureCredential.ts b/sdk/identity/identity/src/credentials/defaultAzureCredential.ts index 0d200e2e2b3b..e67d383c6e0b 100644 --- a/sdk/identity/identity/src/credentials/defaultAzureCredential.ts +++ b/sdk/identity/identity/src/credentials/defaultAzureCredential.ts @@ -44,7 +44,7 @@ interface DefaultCredentialConstructor { * A shim around ManagedIdentityCredential that adapts it to accept * `DefaultAzureCredentialOptions`. * - * + * @internal */ export class DefaultManagedIdentityCredential extends ManagedIdentityCredential { constructor(options?: DefaultAzureCredentialOptions) { diff --git a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts index f4dc1f20f02b..533f0df802ce 100644 --- a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts +++ b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts @@ -61,7 +61,7 @@ describe("ApplicationCredential", function() { }, children: [ { - name: "Azure.Identity.ChainedTokenCredential.getToken", + name: "Azure.Identity.ChainedTokenCredential-getToken", children: [ { name: "Azure.Identity.EnvironmentCredential.getToken", From 2ac198ab4c89b75260da3a72044d4051de40ad4c Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Fri, 6 Aug 2021 17:42:11 -0700 Subject: [PATCH 16/18] update error message --- .../identity/test/public/node/applicationCredential.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts index 533f0df802ce..32372668fee2 100644 --- a/sdk/identity/identity/test/public/node/applicationCredential.spec.ts +++ b/sdk/identity/identity/test/public/node/applicationCredential.spec.ts @@ -85,7 +85,7 @@ describe("ApplicationCredential", function() { console.log(`${error.message}`); assert.ok( error.message.indexOf( - `CredentialUnavailableError: EnvironmentCredential is unavailable. No underlying credential could be used.\nCredentialUnavailableError: ManagedIdentityCredential authentication failed. Message ManagedIdentityCredential - No MSI credential available` + `CredentialUnavailableError: EnvironmentCredential is unavailable. No underlying credential could be used.\nCredentialUnavailableError: ManagedIdentityCredential authentication failed.` ) > -1 ); }); From 1a75abc5661a48c853cceab3e402f0ff34eed161 Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Fri, 6 Aug 2021 18:34:22 -0700 Subject: [PATCH 17/18] added changelog --- sdk/identity/identity/CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sdk/identity/identity/CHANGELOG.md b/sdk/identity/identity/CHANGELOG.md index 097822590e3f..66a8099ddf29 100644 --- a/sdk/identity/identity/CHANGELOG.md +++ b/sdk/identity/identity/CHANGELOG.md @@ -1,9 +1,11 @@ # Release History -## 2.0.0-beta.5 (Unreleased) +## 2.0.0-beta.5 (2021-08-10) ### Features Added +- Implementation of `Application Credential` for use by applications which call into Microsoft Graph APIs and which have issues using `DefaultAzureCredential`. This credential is based on `Environment Credential` and `Managed Identity Credential`. + ### Breaking Changes ### Bugs Fixed @@ -15,6 +17,7 @@ ## 2.0.0-beta.4 (2021-07-07) ### Features Added + - With the dropping of support for Node.js versions that are no longer in LTS, the dependency on `@types/node` has been updated to version 12. Read our [support policy](https://github.com/Azure/azure-sdk-for-js/blob/main/SUPPORT.md) for more details. - Introduced an extension API through a top-level method `useIdentityExtension`. The function accepts an "extension" as an argument, which is a function accepting a `context`. The extension context is an internal part of the Azure Identity API, so it has an `unknown` type. Two new packages are designed to be used with this API: - `@azure/identity-vscode`, which provides the dependencies of `VisualStudioCodeCredential` and enables it (see more below). From 8ea2281825776ca030674409cd622364bfa2ed5f Mon Sep 17 00:00:00 2001 From: Karishma Ghiya Date: Fri, 6 Aug 2021 18:36:52 -0700 Subject: [PATCH 18/18] added changelog --- sdk/identity/identity/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/identity/identity/CHANGELOG.md b/sdk/identity/identity/CHANGELOG.md index a021e59f69a0..4c9294764638 100644 --- a/sdk/identity/identity/CHANGELOG.md +++ b/sdk/identity/identity/CHANGELOG.md @@ -5,7 +5,7 @@ ### Features Added - `ChainedTokenCredential` and `DefaultAzureCredential` now expose a property named `selectedCredential`, which will store the selected credential once any of the available credentials succeeds. -- Implementation of `Application Credential` for use by applications which call into Microsoft Graph APIs and which have issues using `DefaultAzureCredential`. This credential is based on `Environment Credential` and `Managed Identity Credential`. +- Implementation of `ApplicationCredential` for use by applications which call into Microsoft Graph APIs and which have issues using `DefaultAzureCredential`. This credential is based on `EnvironmentCredential` and `ManagedIdentityCredential`. ### Breaking Changes