From d39d1543ea458e51000df21420532f145f484fb8 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Mon, 14 Sep 2020 07:58:38 +1200 Subject: [PATCH 01/10] Begin move of challenge-based auth --- sdk/core/core-http/review/core-http.api.md | 26 ++ sdk/core/core-http/src/coreHttp.ts | 6 + .../challengeBasedAuthenticationPolicy.ts | 241 ++++++++++++++++++ .../keyvault-admin/src/accessControlClient.ts | 2 +- .../keyvault-certificates/src/index.ts | 2 +- .../keyvault-keys/src/cryptographyClient.ts | 2 +- sdk/keyvault/keyvault-keys/src/index.ts | 2 +- sdk/keyvault/keyvault-secrets/src/index.ts | 2 +- 8 files changed, 278 insertions(+), 5 deletions(-) create mode 100644 sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts diff --git a/sdk/core/core-http/review/core-http.api.md b/sdk/core/core-http/review/core-http.api.md index ec6cd89c7816..9dc405a98d4b 100644 --- a/sdk/core/core-http/review/core-http.api.md +++ b/sdk/core/core-http/review/core-http.api.md @@ -49,6 +49,24 @@ export class ApiKeyCredentials implements ServiceClientCredentials { // @public export function applyMixins(targetCtor: any, sourceCtors: any[]): void; +// @public +export class AuthenticationChallenge { + constructor(authorization: string, scope: string); + // (undocumented) + authorization: string; + equalTo(other: AuthenticationChallenge | undefined): boolean; + // (undocumented) + scope: string; +} + +// @public +export class AuthenticationChallengeCache { + // (undocumented) + challenge?: AuthenticationChallenge; + // (undocumented) + setCachedChallenge(challenge: AuthenticationChallenge): void; +} + // @public (undocumented) export type Authenticator = (challenge: object) => Promise; @@ -108,6 +126,9 @@ export class BasicAuthenticationCredentials implements ServiceClientCredentials // @public export function bearerTokenAuthenticationPolicy(credential: TokenCredential, scopes: string | string[]): RequestPolicyFactory; +// @public +export function challengeBasedAuthenticationPolicy(credential: TokenCredential): RequestPolicyFactory; + // @public (undocumented) export interface CompositeMapper extends BaseMapper { // (undocumented) @@ -519,6 +540,11 @@ export interface ParameterValue { value: any; } +// Warning: (ae-forgotten-export) The symbol "ParsedWWWAuthenticate" needs to be exported by the entry point coreHttp.d.ts +// +// @public +export function parseWWWAuthenticate(wwwAuthenticate: string): ParsedWWWAuthenticate; + // @public export function parseXML(str: string, opts?: { includeRoot?: boolean; diff --git a/sdk/core/core-http/src/coreHttp.ts b/sdk/core/core-http/src/coreHttp.ts index 0189f881fc09..4ad67ad19d5f 100644 --- a/sdk/core/core-http/src/coreHttp.ts +++ b/sdk/core/core-http/src/coreHttp.ts @@ -63,6 +63,12 @@ export { getDefaultProxySettings, proxyPolicy } from "./policies/proxyPolicy"; export { redirectPolicy, RedirectOptions } from "./policies/redirectPolicy"; export { keepAlivePolicy, KeepAliveOptions } from "./policies/keepAlivePolicy"; export { disableResponseDecompressionPolicy } from "./policies/disableResponseDecompressionPolicy"; +export { + challengeBasedAuthenticationPolicy, + parseWWWAuthenticate, + AuthenticationChallenge, + AuthenticationChallengeCache +} from "./policies/challengeBasedAuthenticationPolicy"; export { signingPolicy } from "./policies/signingPolicy"; export { userAgentPolicy, diff --git a/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts b/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts new file mode 100644 index 000000000000..3f2b64b54e35 --- /dev/null +++ b/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts @@ -0,0 +1,241 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +import { TokenCredential } from "@azure/core-auth"; +import { + BaseRequestPolicy, + RequestPolicy, + RequestPolicyOptions, + RequestPolicyFactory, +} from "../policies/requestPolicy"; +import { Constants } from "../util/constants"; +import { HttpOperationResponse } from "../httpOperationResponse"; +import { WebResource } from "../webResource"; +import { AccessTokenCache, ExpiringAccessTokenCache } from "../credentials/accessTokenCache"; + +type ValidParsedWWWAuthenticateProperties = + // "authorization_uri" was used in the track 1 version of KeyVault. + // This is not a relevant property anymore, since the service is consistently answering with "authorization". + // | "authorization_uri" + | "authorization" + // Even though the service is moving to "scope", both "resource" and "scope" should be supported. + | "resource" + | "scope"; + +type ParsedWWWAuthenticate = { + [Key in ValidParsedWWWAuthenticateProperties]?: string; +}; + +/** + * Representation of the Authentication Challenge + */ +export class AuthenticationChallenge { + constructor(public authorization: string, public scope: string) {} + + /** + * Checks that this AuthenticationChallenge is equal to another one given. + * Only compares the scope. + * This is exactly what C# is doing, as we can see here: + * https://github.com/Azure/azure-sdk-for-net/blob/70e54b878ff1d01a45266fb3674a396b4ab9c1d2/sdk/keyvault/Azure.Security.KeyVault.Shared/src/ChallengeBasedAuthenticationPolicy.cs#L143-L147 + * @param other The other AuthenticationChallenge + */ + public equalTo(other: AuthenticationChallenge | undefined) { + return other + ? this.scope.toLowerCase() === other.scope.toLowerCase() && + this.authorization.toLowerCase() === other.authorization.toLowerCase() + : false; + } +} + +/** + * Helps keep a copy of any previous authentication challenges, + * so that we can compare on any further request. + */ +export class AuthenticationChallengeCache { + public challenge?: AuthenticationChallenge; + + public setCachedChallenge(challenge: AuthenticationChallenge) { + this.challenge = challenge; + } +} + +/** + * Creates a new ChallengeBasedAuthenticationPolicy factory. + * + * @param credential The TokenCredential implementation that can supply the challenge token. + */ +export function challengeBasedAuthenticationPolicy( + credential: TokenCredential +): RequestPolicyFactory { + const tokenCache: AccessTokenCache = new ExpiringAccessTokenCache(); + const challengeCache = new AuthenticationChallengeCache(); + return { + create: (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => { + return new ChallengeBasedAuthenticationPolicy( + nextPolicy, + options, + credential, + tokenCache, + challengeCache + ); + }, + }; +} + +/** + * Parses an WWW-Authenticate response. + * This transforms a string value like: + * `Bearer authorization="some_authorization", resource="https://some.url"` + * into an object like: + * `{ authorization: "some_authorization", resource: "https://some.url" }` + * @param wwwAuthenticate string value in the WWW-Authenticate header + */ +export function parseWWWAuthenticate(wwwAuthenticate: string): ParsedWWWAuthenticate { + // First we split the string by either `, ` or ` `. + const parts = wwwAuthenticate.split(/,* +/); + // Then we only keep the strings with an equal sign after a word and before a quote. + // also splitting these sections by their equal sign + const keyValues = parts.reduce( + (parts, str) => (str.match(/\w="/) ? [...parts, str.split("=")] : parts), + [] + ); + // Then we transform these key-value pairs back into an object. + const parsed = keyValues.reduce( + (result, [key, value]: string[]) => ({ + ...result, + [key]: value.slice(1, -1), + }), + {} + ); + return parsed; +} + +/** + * + * Provides a RequestPolicy that can request a token from a TokenCredential + * implementation and then apply it to the Authorization header of a request + * as a Bearer token. + * + */ +export class ChallengeBasedAuthenticationPolicy extends BaseRequestPolicy { + private parseWWWAuthenticate: ( + wwwAuthenticate: string + ) => ParsedWWWAuthenticate = parseWWWAuthenticate; + + /** + * Creates a new ChallengeBasedAuthenticationPolicy object. + * + * @param nextPolicy The next RequestPolicy in the request pipeline. + * @param options Options for this RequestPolicy. + * @param credential The TokenCredential implementation that can supply the bearer token. + * @param tokenCache The cache for the most recent AccessToken returned by the TokenCredential. + */ + constructor( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions, + private credential: TokenCredential, + private tokenCache: AccessTokenCache, + private challengeCache: AuthenticationChallengeCache + ) { + super(nextPolicy, options); + } + + /** + * Gets or updates the token from the token cache into the headers of the received web resource. + */ + private async loadToken(webResource: WebResource): Promise { + let accessToken = this.tokenCache.getCachedToken(); + + // If there's no cached token in the cache, we try to get a new one. + if (accessToken === undefined) { + const receivedToken = await this.credential.getToken(this.challengeCache.challenge!.scope); + accessToken = receivedToken || undefined; + this.tokenCache.setCachedToken(accessToken); + } + + if (accessToken) { + webResource.headers.set( + Constants.HeaderConstants.AUTHORIZATION, + `Bearer ${accessToken.token}` + ); + } + } + + /** + * Parses the given WWW-Authenticate header, generates a new AuthenticationChallenge, + * then if the challenge is different from the one cached, resets the token and forces + * a re-authentication, otherwise continues with the existing challenge and token. + * @param wwwAuthenticate Value of the incoming WWW-Authenticate header. + * @param webResource Ongoing HTTP request. + */ + private async regenerateChallenge( + wwwAuthenticate: string, + webResource: WebResource + ): Promise { + // The challenge based authentication will contain both: + // - An authorization URI with a token, + // - The resource to which that token is valid against (also called the scope). + const parsedWWWAuth = this.parseWWWAuthenticate(wwwAuthenticate); + const authorization = parsedWWWAuth.authorization!; + const resource = parsedWWWAuth.resource! || parsedWWWAuth.scope!; + + if (!(authorization && resource)) { + return this._nextPolicy.sendRequest(webResource); + } + + const challenge = new AuthenticationChallenge(authorization, resource + "/.default"); + + // Either if there's no cached challenge at this point (could have happen in parallel), + // or if the cached challenge has a different scope, + // we store the just received challenge and reset the cached token, to force a re-authentication. + if (!this.challengeCache.challenge?.equalTo(challenge)) { + this.challengeCache.setCachedChallenge(challenge); + this.tokenCache.setCachedToken(undefined); + } + + await this.loadToken(webResource); + return this._nextPolicy.sendRequest(webResource); + } + + /** + * Applies the Bearer token to the request through the Authorization header. + * @param webResource Ongoing HTTP request. + */ + public async sendRequest(webResource: WebResource): Promise { + // Ensure that we're about to use a secure connection. + if (!webResource.url.startsWith("https:")) { + throw new Error("The resource address for authorization must use the 'https' protocol."); + } + + // The next request will happen differently whether we have a challenge or not. + let response: HttpOperationResponse; + + if (this.challengeCache.challenge == undefined) { + // If there's no challenge in cache, a blank body will start the challenge. + const originalBody = webResource.body; + webResource.body = ""; + response = await this._nextPolicy.sendRequest(webResource); + webResource.body = originalBody; + } else { + // If we did have a challenge in memory, + // we attempt to load the token from the cache into the request before we try to send the request. + await this.loadToken(webResource); + response = await this._nextPolicy.sendRequest(webResource); + } + + // If we don't receive a response with a 401 status code, + // then we can assume this response has nothing to do with the challenge authentication process. + if (response.status !== 401) { + return response; + } + + // If the response status is 401, we only re-authenticate if the WWW-Authenticate header is present. + const wwwAuthenticate = response.headers.get("WWW-Authenticate"); + if (!wwwAuthenticate) { + return response; + } + + // We re-generate the challenge and see if we have to re-authenticate. + return await this.regenerateChallenge(wwwAuthenticate, webResource); + } +} diff --git a/sdk/keyvault/keyvault-admin/src/accessControlClient.ts b/sdk/keyvault/keyvault-admin/src/accessControlClient.ts index 852e7ea1cda8..0ea763cbc390 100644 --- a/sdk/keyvault/keyvault-admin/src/accessControlClient.ts +++ b/sdk/keyvault/keyvault-admin/src/accessControlClient.ts @@ -10,7 +10,7 @@ import { } from "@azure/core-http"; import { PagedAsyncIterableIterator } from "@azure/core-paging"; -import { challengeBasedAuthenticationPolicy } from "../../keyvault-common/src"; +import { challengeBasedAuthenticationPolicy } from "@azure/core-http"; import { KeyVaultClient } from "./generated/keyVaultClient"; import { RoleAssignmentsCreateResponse, diff --git a/sdk/keyvault/keyvault-certificates/src/index.ts b/sdk/keyvault/keyvault-certificates/src/index.ts index fdccf8be93e6..6fd52078077e 100644 --- a/sdk/keyvault/keyvault-certificates/src/index.ts +++ b/sdk/keyvault/keyvault-certificates/src/index.ts @@ -141,7 +141,7 @@ import { KeyVaultClient } from "./generated/keyVaultClient"; import { SDK_VERSION } from "./generated/utils/constants"; import "@azure/core-paging"; import { PageSettings, PagedAsyncIterableIterator } from "@azure/core-paging"; -import { challengeBasedAuthenticationPolicy } from "../../keyvault-common/src"; +import { challengeBasedAuthenticationPolicy } from "@azure/core-http"; import { CreateCertificatePoller } from "./lro/create/poller"; import { CertificateOperationPoller } from "./lro/operation/poller"; import { DeleteCertificatePoller } from "./lro/delete/poller"; diff --git a/sdk/keyvault/keyvault-keys/src/cryptographyClient.ts b/sdk/keyvault/keyvault-keys/src/cryptographyClient.ts index e9af78404ac8..f6c585dcc571 100644 --- a/sdk/keyvault/keyvault-keys/src/cryptographyClient.ts +++ b/sdk/keyvault/keyvault-keys/src/cryptographyClient.ts @@ -16,7 +16,7 @@ import { Span } from "@opentelemetry/api"; import { logger } from "./log"; import { SDK_VERSION } from "./generated/utils/constants"; import { KeyVaultClient } from "./generated/keyVaultClient"; -import { challengeBasedAuthenticationPolicy } from "../../keyvault-common/src"; +import { challengeBasedAuthenticationPolicy } from "@azure/core-http"; import { LocalSupportedAlgorithmName, diff --git a/sdk/keyvault/keyvault-keys/src/index.ts b/sdk/keyvault/keyvault-keys/src/index.ts index 059ca8d16da4..3ab94a92eeea 100644 --- a/sdk/keyvault/keyvault-keys/src/index.ts +++ b/sdk/keyvault/keyvault-keys/src/index.ts @@ -39,7 +39,7 @@ import { } from "./generated/models"; import { KeyVaultClient } from "./generated/keyVaultClient"; import { SDK_VERSION } from "./generated/utils/constants"; -import { challengeBasedAuthenticationPolicy } from "../../keyvault-common/src"; +import { challengeBasedAuthenticationPolicy } from "@azure/core-http"; import { DeleteKeyPoller } from "./lro/delete/poller"; import { RecoverDeletedKeyPoller } from "./lro/recover/poller"; diff --git a/sdk/keyvault/keyvault-secrets/src/index.ts b/sdk/keyvault/keyvault-secrets/src/index.ts index 7d9493b4934d..5476debccad3 100644 --- a/sdk/keyvault/keyvault-secrets/src/index.ts +++ b/sdk/keyvault/keyvault-secrets/src/index.ts @@ -35,7 +35,7 @@ import { } from "./generated/models"; import { KeyVaultClient } from "./generated/keyVaultClient"; import { SDK_VERSION } from "./generated/utils/constants"; -import { challengeBasedAuthenticationPolicy } from "../../keyvault-common/src"; +import { challengeBasedAuthenticationPolicy } from "@azure/core-http"; import { DeleteSecretPoller } from "./lro/delete/poller"; import { RecoverDeletedSecretPoller } from "./lro/recover/poller"; From b8c7ac15d9a420ef8dee7b2106aea9603e59f39e Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Mon, 14 Sep 2020 07:58:54 +1200 Subject: [PATCH 02/10] Begin move of challenge-based auth --- .../src/policies/challengeBasedAuthenticationPolicy.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts b/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts index 3f2b64b54e35..69f84b22d890 100644 --- a/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts +++ b/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts @@ -6,7 +6,7 @@ import { BaseRequestPolicy, RequestPolicy, RequestPolicyOptions, - RequestPolicyFactory, + RequestPolicyFactory } from "../policies/requestPolicy"; import { Constants } from "../util/constants"; import { HttpOperationResponse } from "../httpOperationResponse"; @@ -78,7 +78,7 @@ export function challengeBasedAuthenticationPolicy( tokenCache, challengeCache ); - }, + } }; } @@ -103,7 +103,7 @@ export function parseWWWAuthenticate(wwwAuthenticate: string): ParsedWWWAuthenti const parsed = keyValues.reduce( (result, [key, value]: string[]) => ({ ...result, - [key]: value.slice(1, -1), + [key]: value.slice(1, -1) }), {} ); From 05df53a9344967ca37b5cf5b55848214e5229a63 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Mon, 14 Sep 2020 08:39:34 +1200 Subject: [PATCH 03/10] Remove keyvault-common --- common/config/rush/pnpm-lock.yaml | 163 +++--------- eng/.docsettings.yml | 1 - rush.json | 5 - sdk/keyvault/keyvault-admin/package.json | 1 - .../keyvault-admin/src/backupClient.ts | 2 +- sdk/keyvault/keyvault-admin/tsconfig.json | 4 +- .../keyvault-certificates/package.json | 1 - ...challengeBasedAuthenticationPolicy.spec.ts | 2 +- .../keyvault-certificates/tsconfig.json | 4 +- sdk/keyvault/keyvault-common/index.ts | 4 - sdk/keyvault/keyvault-common/package.json | 54 ---- .../src/challengeBasedAuthenticationPolicy.ts | 241 ------------------ sdk/keyvault/keyvault-common/src/index.ts | 4 - sdk/keyvault/keyvault-common/tsconfig.json | 11 - sdk/keyvault/keyvault-keys/package.json | 1 - ...challengeBasedAuthenticationPolicy.spec.ts | 2 +- sdk/keyvault/keyvault-keys/tsconfig.json | 4 +- sdk/keyvault/keyvault-secrets/package.json | 1 - ...challengeBasedAuthenticationPolicy.spec.ts | 2 +- sdk/keyvault/keyvault-secrets/tsconfig.json | 4 +- 20 files changed, 46 insertions(+), 465 deletions(-) delete mode 100644 sdk/keyvault/keyvault-common/index.ts delete mode 100644 sdk/keyvault/keyvault-common/package.json delete mode 100644 sdk/keyvault/keyvault-common/src/challengeBasedAuthenticationPolicy.ts delete mode 100644 sdk/keyvault/keyvault-common/src/index.ts delete mode 100644 sdk/keyvault/keyvault-common/tsconfig.json diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 29c9211c9d51..76dbc4902f6b 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -27,7 +27,6 @@ dependencies: '@rush-temp/identity': 'file:projects/identity.tgz' '@rush-temp/keyvault-admin': 'file:projects/keyvault-admin.tgz' '@rush-temp/keyvault-certificates': 'file:projects/keyvault-certificates.tgz' - '@rush-temp/keyvault-common': 'file:projects/keyvault-common.tgz' '@rush-temp/keyvault-keys': 'file:projects/keyvault-keys.tgz' '@rush-temp/keyvault-secrets': 'file:projects/keyvault-secrets.tgz' '@rush-temp/logger': 'file:projects/logger.tgz' @@ -46,8 +45,6 @@ dependencies: '@rush-temp/test-utils-perfstress': 'file:projects/test-utils-perfstress.tgz' '@rush-temp/test-utils-recorder': 'file:projects/test-utils-recorder.tgz' '@rush-temp/testhub': 'file:projects/testhub.tgz' - precise-commits: 1.0.2_prettier@1.19.1 - prettier: 1.19.1 lockfileVersion: 5.1 packages: /@azure/abort-controller/1.0.1: @@ -1827,14 +1824,6 @@ packages: dev: false resolution: integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - /cli-cursor/2.1.0: - dependencies: - restore-cursor: 2.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= /cli-cursor/3.1.0: dependencies: restore-cursor: 3.1.0 @@ -1843,12 +1832,6 @@ packages: node: '>=8' resolution: integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - /cli-spinners/1.3.1: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg== /cli-width/3.0.0: dev: false engines: @@ -2082,14 +2065,6 @@ packages: dev: false resolution: integrity: sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE= - /cross-spawn/5.1.0: - dependencies: - lru-cache: 4.1.5 - shebang-command: 1.2.0 - which: 1.3.1 - dev: false - resolution: - integrity: sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= /cross-spawn/6.0.5: dependencies: nice-try: 1.0.5 @@ -2315,10 +2290,6 @@ packages: dev: false resolution: integrity: sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw= - /diff-match-patch/1.0.5: - dev: false - resolution: - integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw== /diff/3.5.0: dev: false engines: @@ -2872,20 +2843,6 @@ packages: node: '>=0.8.x' resolution: integrity: sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== - /execa/0.9.0: - dependencies: - cross-spawn: 5.1.0 - get-stream: 3.0.0 - is-stream: 1.1.0 - npm-run-path: 2.0.2 - p-finally: 1.0.0 - signal-exit: 3.0.3 - strip-eof: 1.0.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA== /execa/1.0.0: dependencies: cross-spawn: 6.0.5 @@ -3378,12 +3335,6 @@ packages: node: '>=4' resolution: integrity: sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== - /get-stream/3.0.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= /get-stream/4.1.0: dependencies: pump: 3.0.0 @@ -3811,10 +3762,6 @@ packages: dev: false resolution: integrity: sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - /ignore/3.3.10: - dev: false - resolution: - integrity: sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== /ignore/4.0.6: dev: false engines: @@ -5041,12 +4988,6 @@ packages: hasBin: true resolution: integrity: sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA== - /mimic-fn/1.2.0: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== /mimic-fn/2.1.0: dev: false engines: @@ -5160,12 +5101,6 @@ packages: dev: false resolution: integrity: sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ== - /mri/1.1.6: - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ== /ms/2.0.0: dev: false resolution: @@ -5473,14 +5408,6 @@ packages: dev: false resolution: integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - /onetime/2.0.1: - dependencies: - mimic-fn: 1.2.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= /onetime/5.1.0: dependencies: mimic-fn: 2.1.0 @@ -5511,17 +5438,6 @@ packages: node: '>= 0.8.0' resolution: integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - /ora/1.4.0: - dependencies: - chalk: 2.4.2 - cli-cursor: 2.1.0 - cli-spinners: 1.3.1 - log-symbols: 2.2.0 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha512-iMK1DOQxzzh2MBlVsU42G80mnrvUhqsMh74phHtDlrcTZPK0pH6o7l7DRshK+0YsxDyEuaOkziVdvM3T0QTzpw== /os-homedir/1.0.2: dev: false engines: @@ -5884,22 +5800,6 @@ packages: hasBin: true resolution: integrity: sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g== - /precise-commits/1.0.2_prettier@1.19.1: - dependencies: - diff-match-patch: 1.0.5 - execa: 0.9.0 - find-up: 2.1.0 - glob: 7.1.6 - ignore: 3.3.10 - mri: 1.1.6 - ora: 1.4.0 - prettier: 1.19.1 - dev: false - hasBin: true - peerDependencies: - prettier: '>=1.8.0' - resolution: - integrity: sha512-PYkoNTFXVvZRzJTDxdgzmPanhSNGj5Wtj2NgSo7IhwNXGcKktX+L4DJhyIrhFSLsWWAvd+cYyyU2eXlaX5QxzA== /prelude-ls/1.1.2: dev: false engines: @@ -6401,15 +6301,6 @@ packages: dev: false resolution: integrity: sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== - /restore-cursor/2.0.0: - dependencies: - onetime: 2.0.1 - signal-exit: 3.0.3 - dev: false - engines: - node: '>=4' - resolution: - integrity: sha1-n37ih/gv0ybU/RYpI9YhKe7g368= /restore-cursor/3.1.0: dependencies: onetime: 5.1.0 @@ -9178,7 +9069,7 @@ packages: dev: false name: '@rush-temp/event-hubs' resolution: - integrity: sha512-N9NwpcM2OZ/H/63xYaGo+0FGxhFi7CmUQW+CW7RdEMt/nnm+ssWoCvVdHvDflBBwxFqgRfqQevgiBHmB/EQ5uQ== + integrity: sha512-jY4Yvmtu9YSd6dLPezEwmEtggvxAS/MvarrynifBWCjF4SoWmZvc1O2EZdZYTxdYjysYn8I4O3RkaFEnSwNu4w== tarball: 'file:projects/event-hubs.tgz' version: 0.0.0 'file:projects/event-processor-host.tgz': @@ -9360,7 +9251,7 @@ packages: dev: false name: '@rush-temp/eventhubs-checkpointstore-blob' resolution: - integrity: sha512-65Cx97+k1+Yzlj8MrjNfseuYUG4+egdVh07Ma18ImzXOI1LKHKodWie3Dg9u2Wn4/hlagKE9qPZyrxNJKq4utg== + integrity: sha512-w5AuQEI72MPTBOJE5PkBcl3R/unve12sfjW2aFjQQYtWxP/d8hXO7iL0Yptk4mmcauIDVHchSNIO5rTeebcMyg== tarball: 'file:projects/eventhubs-checkpointstore-blob.tgz' version: 0.0.0 'file:projects/identity.tgz': @@ -9428,6 +9319,7 @@ packages: 'file:projects/keyvault-admin.tgz': dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.1.0 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -9435,16 +9327,40 @@ packages: '@rollup/plugin-multi-entry': 3.0.1_rollup@1.32.1 '@rollup/plugin-node-resolve': 8.1.0_rollup@1.32.1 '@rollup/plugin-replace': 2.3.3_rollup@1.32.1 + '@types/chai': 4.2.11 + '@types/fs-extra': 8.1.1 + '@types/mocha': 7.0.2 '@types/node': 8.10.61 + '@types/sinon': 9.0.4 + '@types/uuid': 8.0.0 '@typescript-eslint/eslint-plugin': 2.34.0_3787943315ebc5ea524d5c102dc9e452 '@typescript-eslint/parser': 2.34.0_eslint@6.8.0+typescript@3.9.6 + assert: 1.5.0 + chai: 4.2.0 cross-env: 7.0.2 + dotenv: 8.2.0 eslint: 6.8.0 eslint-config-prettier: 6.11.0_eslint@6.8.0 eslint-plugin-no-null: 1.0.2_eslint@6.8.0 eslint-plugin-no-only-tests: 2.4.0 eslint-plugin-promise: 4.2.1 esm: 3.2.25 + karma: 5.1.1 + karma-chrome-launcher: 3.1.0 + karma-coverage: 2.0.2 + karma-edge-launcher: 0.4.2_karma@5.1.1 + karma-env-preprocessor: 0.1.1 + karma-firefox-launcher: 1.3.0 + karma-ie-launcher: 1.0.0_karma@5.1.1 + karma-json-preprocessor: 0.3.3_karma@5.1.1 + karma-json-to-file-reporter: 1.0.1 + karma-junit-reporter: 2.0.1_karma@5.1.1 + karma-mocha: 2.0.1 + karma-mocha-reporter: 2.2.5_karma@5.1.1 + karma-remap-istanbul: 0.6.0_karma@5.1.1 + mocha: 7.2.0 + mocha-junit-reporter: 1.23.3_mocha@7.2.0 + nyc: 14.1.1 prettier: 1.19.1 rimraf: 3.0.2 rollup: 1.32.1 @@ -9452,13 +9368,15 @@ packages: rollup-plugin-sourcemaps: 0.4.2_rollup@1.32.1 rollup-plugin-terser: 5.3.0_rollup@1.32.1 rollup-plugin-visualizer: 4.0.4_rollup@1.32.1 + sinon: 9.0.2 source-map-support: 0.5.19 tslib: 2.0.0 typescript: 3.9.6 + uuid: 8.2.0 dev: false name: '@rush-temp/keyvault-admin' resolution: - integrity: sha512-eJjxCTqMLb7tC0iSwnDg/sXQpv/89fgdgtuMTfFMnx7nM+30n/L8qTwXhBQs87UucOKDQI3qSw8DD74fs7xGvg== + integrity: sha512-6f8De+04Tlf3rZOc/1Thy6H7qGD6/5rcn0fH9FPXudEe+Vbr7Vx3f4HhsnUDy9vnVrvyNWfFyiCJoGT0drXpow== tarball: 'file:projects/keyvault-admin.tgz' version: 0.0.0 'file:projects/keyvault-certificates.tgz': @@ -9524,19 +9442,9 @@ packages: dev: false name: '@rush-temp/keyvault-certificates' resolution: - integrity: sha512-+a86qI+0rcf+xiFjB3H4JH6htEoBP+JJvVNmoNtfcLRh4F//9PBzFxOoS0NKutNsdw6Qexlv9lF0zJhj2E9uAA== + integrity: sha512-yDAV8Si946hzwpcxzkApINOt1n/qEu1IntnvPqMCOrEqbov++DRkg3H4SjGDe7IZKF4kGV2lweazuvBH6w7uKA== tarball: 'file:projects/keyvault-certificates.tgz' version: 0.0.0 - 'file:projects/keyvault-common.tgz': - dependencies: - tslib: 2.0.0 - typescript: 3.9.6 - dev: false - name: '@rush-temp/keyvault-common' - resolution: - integrity: sha512-cCbZ1kryFHZNYwGfQj2bRfG6vvwVlPXFWU12cKfc1Xps5KYGcPfIKTbZsOfbMw8SCM/FcLnImZeideZQ3lxXPA== - tarball: 'file:projects/keyvault-common.tgz' - version: 0.0.0 'file:projects/keyvault-keys.tgz': dependencies: '@azure/core-tracing': 1.0.0-preview.9 @@ -10008,7 +9916,7 @@ packages: dev: false name: '@rush-temp/service-bus' resolution: - integrity: sha512-cYaXwp6B+xEGX4UT/CUvJvdjYrGMrktVgrNO2gHP4NBtR6du9wPoGYgOvN8AeHqnOUeafa304Pi3xr6BMW3RmA== + integrity: sha512-yUNItoZnv5e6MhbT7s5BEKkJ/aXAn+He9qxRb6hEQjnweh3vpR4YxsRzTNnAYrAxcnlksrx0OpGjL3/gsI3Olw== tarball: 'file:projects/service-bus.tgz' version: 0.0.0 'file:projects/storage-blob-changefeed.tgz': @@ -10072,7 +9980,7 @@ packages: dev: false name: '@rush-temp/storage-blob-changefeed' resolution: - integrity: sha512-RseYHrce+kc7QnHXtD9/5MBizgp2GY2+/AMiUfhCHl0FS1lyhWfhnFP3ctDfbfWcxg6jvXqOcnKdd5BTIM2aeg== + integrity: sha512-kiQsE6/mLEB5LZoGZFSgH+PgkeeBETkp1HUoTLwYd8IK6WgUaU63hc7FO8LYESW0oP05LeJdVLTtMA5jc2uK9g== tarball: 'file:projects/storage-blob-changefeed.tgz' version: 0.0.0 'file:projects/storage-blob.tgz': @@ -10201,7 +10109,7 @@ packages: dev: false name: '@rush-temp/storage-file-datalake' resolution: - integrity: sha512-kr4Mann4jmvHJ5jrDYz7iuaPLXU22DytwownUq9OgFd0Z2vVrMXtTX1SVeqDw4byNpYv3o+kPtpR3YWO8ikpsQ== + integrity: sha512-T5+VpauSuj3fPBJ7jLMk3qgnFVihSVQjcABp/XHalvOBJWV9RbLpNBNyHKhheJumjvLHFVWBcZQ63xUF46Ag6w== tarball: 'file:projects/storage-file-datalake.tgz' version: 0.0.0 'file:projects/storage-file-share.tgz': @@ -10580,7 +10488,6 @@ specifiers: '@rush-temp/identity': 'file:./projects/identity.tgz' '@rush-temp/keyvault-admin': 'file:./projects/keyvault-admin.tgz' '@rush-temp/keyvault-certificates': 'file:./projects/keyvault-certificates.tgz' - '@rush-temp/keyvault-common': 'file:./projects/keyvault-common.tgz' '@rush-temp/keyvault-keys': 'file:./projects/keyvault-keys.tgz' '@rush-temp/keyvault-secrets': 'file:./projects/keyvault-secrets.tgz' '@rush-temp/logger': 'file:./projects/logger.tgz' @@ -10599,5 +10506,3 @@ specifiers: '@rush-temp/test-utils-perfstress': 'file:./projects/test-utils-perfstress.tgz' '@rush-temp/test-utils-recorder': 'file:./projects/test-utils-recorder.tgz' '@rush-temp/testhub': 'file:./projects/testhub.tgz' - precise-commits: ^1.0.2 - prettier: ^1.16.4 diff --git a/eng/.docsettings.yml b/eng/.docsettings.yml index 586305ee5d71..dbc8c1402270 100644 --- a/eng/.docsettings.yml +++ b/eng/.docsettings.yml @@ -7,7 +7,6 @@ omitted_paths: - sdk/identity/identity/test/manual-integration/* - sdk/test-utils/perfstress/README.md - sdk/keyvault/*/test/README.md - - sdk/keyvault/keyvault-common/* - sdk/appconfiguration/*/test/README.md - sdk/eventhub/*/test/README.md - sdk/search/*/test/README.md diff --git a/rush.json b/rush.json index c816a9e34d11..81519c9c6c68 100644 --- a/rush.json +++ b/rush.json @@ -452,11 +452,6 @@ "projectFolder": "sdk/identity/identity", "versionPolicyName": "client" }, - { - "packageName": "@azure/keyvault-common", - "projectFolder": "sdk/keyvault/keyvault-common", - "versionPolicyName": "utility" - }, { "packageName": "@azure/keyvault-admin", "projectFolder": "sdk/keyvault/keyvault-admin", diff --git a/sdk/keyvault/keyvault-admin/package.json b/sdk/keyvault/keyvault-admin/package.json index 8979ec4078b6..2586e4c88eed 100644 --- a/sdk/keyvault/keyvault-admin/package.json +++ b/sdk/keyvault/keyvault-admin/package.json @@ -37,7 +37,6 @@ "dist/", "dist-browser/", "dist-esm/keyvault-admin/src", - "dist-esm/keyvault-common/src", "README.md", "LICENSE" ], diff --git a/sdk/keyvault/keyvault-admin/src/backupClient.ts b/sdk/keyvault/keyvault-admin/src/backupClient.ts index 94ee65b2185c..cea85b5d7996 100644 --- a/sdk/keyvault/keyvault-admin/src/backupClient.ts +++ b/sdk/keyvault/keyvault-admin/src/backupClient.ts @@ -9,7 +9,7 @@ import { } from "@azure/core-http"; import { PollerLike } from "@azure/core-lro"; -import { challengeBasedAuthenticationPolicy } from "../../keyvault-common"; +import { challengeBasedAuthenticationPolicy } from "@azure/core-http"; import { KeyVaultClient } from "./generated/keyVaultClient"; import { BackupClientOptions, BeginBackupOptions, BeginRestoreOptions } from "./backupClientModels"; import { LATEST_API_VERSION, SDK_VERSION } from "./constants"; diff --git a/sdk/keyvault/keyvault-admin/tsconfig.json b/sdk/keyvault/keyvault-admin/tsconfig.json index 39e5962ffd82..f832d612bc4c 100644 --- a/sdk/keyvault/keyvault-admin/tsconfig.json +++ b/sdk/keyvault/keyvault-admin/tsconfig.json @@ -5,6 +5,6 @@ "outDir": "./dist-esm", "resolveJsonModule": true }, - "exclude": ["node_modules", "../keyvault-common/node_modules", "./samples/**/*.ts"], - "include": ["./src/**/*.ts", "./test/**/*.ts", "../keyvault-common/**/*.ts"] + "exclude": ["node_modules", "./samples/**/*.ts"], + "include": ["./src/**/*.ts", "./test/**/*.ts"] } diff --git a/sdk/keyvault/keyvault-certificates/package.json b/sdk/keyvault/keyvault-certificates/package.json index 8044a7222dca..0ec881a68bf6 100644 --- a/sdk/keyvault/keyvault-certificates/package.json +++ b/sdk/keyvault/keyvault-certificates/package.json @@ -30,7 +30,6 @@ "dist/", "dist-browser/", "dist-esm/keyvault-certificates/src", - "dist-esm/keyvault-common/src", "README.md", "LICENSE" ], diff --git a/sdk/keyvault/keyvault-certificates/test/internal/challengeBasedAuthenticationPolicy.spec.ts b/sdk/keyvault/keyvault-certificates/test/internal/challengeBasedAuthenticationPolicy.spec.ts index 4e521a888aa7..d2cc01c47936 100644 --- a/sdk/keyvault/keyvault-certificates/test/internal/challengeBasedAuthenticationPolicy.spec.ts +++ b/sdk/keyvault/keyvault-certificates/test/internal/challengeBasedAuthenticationPolicy.spec.ts @@ -9,7 +9,7 @@ import { AuthenticationChallengeCache, AuthenticationChallenge, parseWWWAuthenticate -} from "../../../keyvault-common/src"; +} from "@azure/core-http"; import { CertificateClient } from "../../src"; import { testPollerProperties } from "../utils/recorderUtils"; import { authenticate } from "../utils/testAuthentication"; diff --git a/sdk/keyvault/keyvault-certificates/tsconfig.json b/sdk/keyvault/keyvault-certificates/tsconfig.json index 7a5252578c4f..212dbe5699c6 100644 --- a/sdk/keyvault/keyvault-certificates/tsconfig.json +++ b/sdk/keyvault/keyvault-certificates/tsconfig.json @@ -6,6 +6,6 @@ "lib": ["dom"], "resolveJsonModule": true }, - "exclude": ["node_modules", "../keyvault-common/node_modules", "./samples/**/*.ts"], - "include": ["./src/**/*.ts", "./test/**/*.ts", "../keyvault-common/**/*.ts"] + "exclude": ["node_modules", "./samples/**/*.ts"], + "include": ["./src/**/*.ts", "./test/**/*.ts"] } diff --git a/sdk/keyvault/keyvault-common/index.ts b/sdk/keyvault/keyvault-common/index.ts deleted file mode 100644 index a2b24231e7f5..000000000000 --- a/sdk/keyvault/keyvault-common/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -export * from "./src"; diff --git a/sdk/keyvault/keyvault-common/package.json b/sdk/keyvault/keyvault-common/package.json deleted file mode 100644 index 6ccd36d0602b..000000000000 --- a/sdk/keyvault/keyvault-common/package.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "name": "@azure/keyvault-common", - "sideEffects": false, - "private": true, - "author": "Microsoft Corporation", - "version": "1.0.0", - "license": "MIT", - "description": "Common internal functionality for all of the Azure Key Vault clients in the Azure SDK for JavaScript", - "repository": "github:Azure/azure-sdk-for-js", - "main": "./src/index.ts", - "module": "dist-esm/index.js", - "types": "./types/index.d.ts", - "engines": { - "node": ">=8.0.0" - }, - "scripts": { - "audit": "echo skipped", - "build:samples": "echo skipped", - "build:es6": "tsc -p tsconfig.json", - "build:nodebrowser": "echo skipped", - "build:test": "echo skipped", - "build": "npm run extract-api && npm run build:es6 && npm run build:nodebrowser", - "check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", - "clean": "rimraf dist-esm dist-test typings *.tgz *.log samples/typescript/dist", - "execute:js-samples": "echo skipped", - "execute:ts-samples": "echo skipped", - "execute:samples": "npm run build:samples && npm run execute:js-samples && npm run execute:ts-samples", - "extract-api": "echo skipped", - "format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"*.{js,json}\"", - "integration-test:browser": "echo skipped", - "integration-test:node": "echo skipped", - "integration-test:node:no-timeout": "echo skipped", - "integration-test": "npm run integration-test:node && npm run integration-test:browser", - "lint:fix": "eslint package.json src --ext .ts --fix --fix-type [problem,suggestion]", - "lint": "eslint src --ext .ts -f html -o search-lintReport.html || exit 0", - "lint:terminal": "eslint src --ext .ts", - "pack": "npm pack 2>&1", - "prebuild": "npm run clean", - "test:browser": "npm run clean && npm run build:test && npm run unit-test:browser", - "test:node": "npm run clean && npm run build:test && npm run unit-test:node", - "test": "npm run clean && npm run build:test && npm run unit-test", - "unit-test:browser": "echo skipped", - "unit-test:node": "echo skipped", - "unit-test:node:no-timeout": "echo skipped", - "unit-test": "npm run unit-test:node && npm run unit-test:browser" - }, - "dependencies": { - "@azure/core-http": "^1.1.6", - "tslib": "^2.0.0" - }, - "devDependencies": { - "typescript": "~3.9.3" - } -} diff --git a/sdk/keyvault/keyvault-common/src/challengeBasedAuthenticationPolicy.ts b/sdk/keyvault/keyvault-common/src/challengeBasedAuthenticationPolicy.ts deleted file mode 100644 index 2539bcd4e4a1..000000000000 --- a/sdk/keyvault/keyvault-common/src/challengeBasedAuthenticationPolicy.ts +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -import { TokenCredential } from "@azure/core-http"; -import { - BaseRequestPolicy, - RequestPolicy, - RequestPolicyOptions, - RequestPolicyFactory, -} from "@azure/core-http"; -import { Constants } from "@azure/core-http"; -import { HttpOperationResponse } from "@azure/core-http"; -import { WebResource } from "@azure/core-http"; -import { AccessTokenCache, ExpiringAccessTokenCache } from "@azure/core-http"; - -type ValidParsedWWWAuthenticateProperties = - // "authorization_uri" was used in the track 1 version of KeyVault. - // This is not a relevant property anymore, since the service is consistently answering with "authorization". - // | "authorization_uri" - | "authorization" - // Even though the service is moving to "scope", both "resource" and "scope" should be supported. - | "resource" - | "scope"; - -type ParsedWWWAuthenticate = { - [Key in ValidParsedWWWAuthenticateProperties]?: string; -}; - -/** - * Representation of the Authentication Challenge - */ -export class AuthenticationChallenge { - constructor(public authorization: string, public scope: string) {} - - /** - * Checks that this AuthenticationChallenge is equal to another one given. - * Only compares the scope. - * This is exactly what C# is doing, as we can see here: - * https://github.com/Azure/azure-sdk-for-net/blob/70e54b878ff1d01a45266fb3674a396b4ab9c1d2/sdk/keyvault/Azure.Security.KeyVault.Shared/src/ChallengeBasedAuthenticationPolicy.cs#L143-L147 - * @param other The other AuthenticationChallenge - */ - public equalTo(other: AuthenticationChallenge | undefined) { - return other - ? this.scope.toLowerCase() === other.scope.toLowerCase() && - this.authorization.toLowerCase() === other.authorization.toLowerCase() - : false; - } -} - -/** - * Helps keep a copy of any previous authentication challenges, - * so that we can compare on any further request. - */ -export class AuthenticationChallengeCache { - public challenge?: AuthenticationChallenge; - - public setCachedChallenge(challenge: AuthenticationChallenge) { - this.challenge = challenge; - } -} - -/** - * Creates a new ChallengeBasedAuthenticationPolicy factory. - * - * @param credential The TokenCredential implementation that can supply the challenge token. - */ -export function challengeBasedAuthenticationPolicy( - credential: TokenCredential -): RequestPolicyFactory { - const tokenCache: AccessTokenCache = new ExpiringAccessTokenCache(); - const challengeCache = new AuthenticationChallengeCache(); - return { - create: (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => { - return new ChallengeBasedAuthenticationPolicy( - nextPolicy, - options, - credential, - tokenCache, - challengeCache - ); - }, - }; -} - -/** - * Parses an WWW-Authenticate response. - * This transforms a string value like: - * `Bearer authorization="some_authorization", resource="https://some.url"` - * into an object like: - * `{ authorization: "some_authorization", resource: "https://some.url" }` - * @param wwwAuthenticate string value in the WWW-Authenticate header - */ -export function parseWWWAuthenticate(wwwAuthenticate: string): ParsedWWWAuthenticate { - // First we split the string by either `, ` or ` `. - const parts = wwwAuthenticate.split(/,* +/); - // Then we only keep the strings with an equal sign after a word and before a quote. - // also splitting these sections by their equal sign - const keyValues = parts.reduce( - (parts, str) => (str.match(/\w="/) ? [...parts, str.split("=")] : parts), - [] - ); - // Then we transform these key-value pairs back into an object. - const parsed = keyValues.reduce( - (result, [key, value]: string[]) => ({ - ...result, - [key]: value.slice(1, -1), - }), - {} - ); - return parsed; -} - -/** - * - * Provides a RequestPolicy that can request a token from a TokenCredential - * implementation and then apply it to the Authorization header of a request - * as a Bearer token. - * - */ -export class ChallengeBasedAuthenticationPolicy extends BaseRequestPolicy { - private parseWWWAuthenticate: ( - wwwAuthenticate: string - ) => ParsedWWWAuthenticate = parseWWWAuthenticate; - - /** - * Creates a new ChallengeBasedAuthenticationPolicy object. - * - * @param nextPolicy The next RequestPolicy in the request pipeline. - * @param options Options for this RequestPolicy. - * @param credential The TokenCredential implementation that can supply the bearer token. - * @param tokenCache The cache for the most recent AccessToken returned by the TokenCredential. - */ - constructor( - nextPolicy: RequestPolicy, - options: RequestPolicyOptions, - private credential: TokenCredential, - private tokenCache: AccessTokenCache, - private challengeCache: AuthenticationChallengeCache - ) { - super(nextPolicy, options); - } - - /** - * Gets or updates the token from the token cache into the headers of the received web resource. - */ - private async loadToken(webResource: WebResource): Promise { - let accessToken = this.tokenCache.getCachedToken(); - - // If there's no cached token in the cache, we try to get a new one. - if (accessToken === undefined) { - const receivedToken = await this.credential.getToken(this.challengeCache.challenge!.scope); - accessToken = receivedToken || undefined; - this.tokenCache.setCachedToken(accessToken); - } - - if (accessToken) { - webResource.headers.set( - Constants.HeaderConstants.AUTHORIZATION, - `Bearer ${accessToken.token}` - ); - } - } - - /** - * Parses the given WWW-Authenticate header, generates a new AuthenticationChallenge, - * then if the challenge is different from the one cached, resets the token and forces - * a re-authentication, otherwise continues with the existing challenge and token. - * @param wwwAuthenticate Value of the incoming WWW-Authenticate header. - * @param webResource Ongoing HTTP request. - */ - private async regenerateChallenge( - wwwAuthenticate: string, - webResource: WebResource - ): Promise { - // The challenge based authentication will contain both: - // - An authorization URI with a token, - // - The resource to which that token is valid against (also called the scope). - const parsedWWWAuth = this.parseWWWAuthenticate(wwwAuthenticate); - const authorization = parsedWWWAuth.authorization!; - const resource = parsedWWWAuth.resource! || parsedWWWAuth.scope!; - - if (!(authorization && resource)) { - return this._nextPolicy.sendRequest(webResource); - } - - const challenge = new AuthenticationChallenge(authorization, resource + "/.default"); - - // Either if there's no cached challenge at this point (could have happen in parallel), - // or if the cached challenge has a different scope, - // we store the just received challenge and reset the cached token, to force a re-authentication. - if (!this.challengeCache.challenge?.equalTo(challenge)) { - this.challengeCache.setCachedChallenge(challenge); - this.tokenCache.setCachedToken(undefined); - } - - await this.loadToken(webResource); - return this._nextPolicy.sendRequest(webResource); - } - - /** - * Applies the Bearer token to the request through the Authorization header. - * @param webResource Ongoing HTTP request. - */ - public async sendRequest(webResource: WebResource): Promise { - // Ensure that we're about to use a secure connection. - if (!webResource.url.startsWith("https:")) { - throw new Error("The resource address for authorization must use the 'https' protocol."); - } - - // The next request will happen differently whether we have a challenge or not. - let response: HttpOperationResponse; - - if (this.challengeCache.challenge == undefined) { - // If there's no challenge in cache, a blank body will start the challenge. - const originalBody = webResource.body; - webResource.body = ""; - response = await this._nextPolicy.sendRequest(webResource); - webResource.body = originalBody; - } else { - // If we did have a challenge in memory, - // we attempt to load the token from the cache into the request before we try to send the request. - await this.loadToken(webResource); - response = await this._nextPolicy.sendRequest(webResource); - } - - // If we don't receive a response with a 401 status code, - // then we can assume this response has nothing to do with the challenge authentication process. - if (response.status !== 401) { - return response; - } - - // If the response status is 401, we only re-authenticate if the WWW-Authenticate header is present. - const wwwAuthenticate = response.headers.get("WWW-Authenticate"); - if (!wwwAuthenticate) { - return response; - } - - // We re-generate the challenge and see if we have to re-authenticate. - return await this.regenerateChallenge(wwwAuthenticate, webResource); - } -} diff --git a/sdk/keyvault/keyvault-common/src/index.ts b/sdk/keyvault/keyvault-common/src/index.ts deleted file mode 100644 index 6b3ad96773fa..000000000000 --- a/sdk/keyvault/keyvault-common/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -export * from "./challengeBasedAuthenticationPolicy"; diff --git a/sdk/keyvault/keyvault-common/tsconfig.json b/sdk/keyvault/keyvault-common/tsconfig.json deleted file mode 100644 index 2936b15768d1..000000000000 --- a/sdk/keyvault/keyvault-common/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "../../../tsconfig.package", - "compilerOptions": { - "declarationDir": "./types", - "outDir": "./dist-esm", - "lib": ["dom"], - "resolveJsonModule": true - }, - "exclude": ["node_modules"], - "include": ["./src/**/*.ts"] -} diff --git a/sdk/keyvault/keyvault-keys/package.json b/sdk/keyvault/keyvault-keys/package.json index 48fa08b327ef..c38b3e15de5d 100644 --- a/sdk/keyvault/keyvault-keys/package.json +++ b/sdk/keyvault/keyvault-keys/package.json @@ -30,7 +30,6 @@ "dist/", "dist-browser/", "dist-esm/keyvault-keys/src", - "dist-esm/keyvault-common/src", "README.md", "LICENSE" ], diff --git a/sdk/keyvault/keyvault-keys/test/internal/challengeBasedAuthenticationPolicy.spec.ts b/sdk/keyvault/keyvault-keys/test/internal/challengeBasedAuthenticationPolicy.spec.ts index b4b116efc511..fd92a746bcc0 100644 --- a/sdk/keyvault/keyvault-keys/test/internal/challengeBasedAuthenticationPolicy.spec.ts +++ b/sdk/keyvault/keyvault-keys/test/internal/challengeBasedAuthenticationPolicy.spec.ts @@ -9,7 +9,7 @@ import { AuthenticationChallengeCache, AuthenticationChallenge, parseWWWAuthenticate -} from "../../../keyvault-common/src"; +} from "@azure/core-http"; import { KeyClient } from "../../src"; import { authenticate } from "../utils/testAuthentication"; import TestClient from "../utils/testClient"; diff --git a/sdk/keyvault/keyvault-keys/tsconfig.json b/sdk/keyvault/keyvault-keys/tsconfig.json index 7a5252578c4f..212dbe5699c6 100644 --- a/sdk/keyvault/keyvault-keys/tsconfig.json +++ b/sdk/keyvault/keyvault-keys/tsconfig.json @@ -6,6 +6,6 @@ "lib": ["dom"], "resolveJsonModule": true }, - "exclude": ["node_modules", "../keyvault-common/node_modules", "./samples/**/*.ts"], - "include": ["./src/**/*.ts", "./test/**/*.ts", "../keyvault-common/**/*.ts"] + "exclude": ["node_modules", "./samples/**/*.ts"], + "include": ["./src/**/*.ts", "./test/**/*.ts"] } diff --git a/sdk/keyvault/keyvault-secrets/package.json b/sdk/keyvault/keyvault-secrets/package.json index dca0790f9098..e44ec4d410b6 100644 --- a/sdk/keyvault/keyvault-secrets/package.json +++ b/sdk/keyvault/keyvault-secrets/package.json @@ -33,7 +33,6 @@ "dist/", "dist-browser/", "dist-esm/keyvault-secrets/src", - "dist-esm/keyvault-common/src", "README.md", "LICENSE" ], diff --git a/sdk/keyvault/keyvault-secrets/test/internal/challengeBasedAuthenticationPolicy.spec.ts b/sdk/keyvault/keyvault-secrets/test/internal/challengeBasedAuthenticationPolicy.spec.ts index 93b07af149e2..d119c63f90e8 100644 --- a/sdk/keyvault/keyvault-secrets/test/internal/challengeBasedAuthenticationPolicy.spec.ts +++ b/sdk/keyvault/keyvault-secrets/test/internal/challengeBasedAuthenticationPolicy.spec.ts @@ -9,7 +9,7 @@ import { AuthenticationChallengeCache, AuthenticationChallenge, parseWWWAuthenticate -} from "../../../keyvault-common/src"; +} from "@azure/core-http"; import { SecretClient } from "../../src"; import { authenticate } from "../utils/testAuthentication"; import TestClient from "../utils/testClient"; diff --git a/sdk/keyvault/keyvault-secrets/tsconfig.json b/sdk/keyvault/keyvault-secrets/tsconfig.json index 7a5252578c4f..212dbe5699c6 100644 --- a/sdk/keyvault/keyvault-secrets/tsconfig.json +++ b/sdk/keyvault/keyvault-secrets/tsconfig.json @@ -6,6 +6,6 @@ "lib": ["dom"], "resolveJsonModule": true }, - "exclude": ["node_modules", "../keyvault-common/node_modules", "./samples/**/*.ts"], - "include": ["./src/**/*.ts", "./test/**/*.ts", "../keyvault-common/**/*.ts"] + "exclude": ["node_modules", "./samples/**/*.ts"], + "include": ["./src/**/*.ts", "./test/**/*.ts"] } From e86d4f74479191c17dcce3e661492fc3c03128cc Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Mon, 14 Sep 2020 09:33:46 +1200 Subject: [PATCH 04/10] Update paths --- sdk/keyvault/keyvault-admin/api-extractor.json | 2 +- sdk/keyvault/keyvault-admin/rollup.base.config.js | 4 ++-- sdk/keyvault/keyvault-certificates/api-extractor.json | 2 +- sdk/keyvault/keyvault-certificates/rollup.base.config.js | 4 ++-- sdk/keyvault/keyvault-keys/api-extractor.json | 2 +- sdk/keyvault/keyvault-keys/rollup.base.config.js | 4 ++-- sdk/keyvault/keyvault-secrets/api-extractor.json | 2 +- sdk/keyvault/keyvault-secrets/rollup.base.config.js | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sdk/keyvault/keyvault-admin/api-extractor.json b/sdk/keyvault/keyvault-admin/api-extractor.json index c0d4f1b5dc2b..7fc6e5f11b8e 100644 --- a/sdk/keyvault/keyvault-admin/api-extractor.json +++ b/sdk/keyvault/keyvault-admin/api-extractor.json @@ -1,6 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "types/keyvault-admin/src/index.d.ts", + "mainEntryPointFilePath": "types/src/index.d.ts", "docModel": { "enabled": true }, diff --git a/sdk/keyvault/keyvault-admin/rollup.base.config.js b/sdk/keyvault/keyvault-admin/rollup.base.config.js index 7e83d92eb0cc..acb23c4c8fea 100644 --- a/sdk/keyvault/keyvault-admin/rollup.base.config.js +++ b/sdk/keyvault/keyvault-admin/rollup.base.config.js @@ -33,7 +33,7 @@ export function nodeConfig(test = false) { const externalNodeBuiltins = []; const additionalExternals = []; const baseConfig = { - input: "dist-esm/keyvault-admin/src/index.js", + input: "dist-esm/src/index.js", external: depNames.concat(externalNodeBuiltins, additionalExternals), output: { file: "dist/index.js", @@ -83,7 +83,7 @@ export function nodeConfig(test = false) { export function browserConfig(test = false) { const baseConfig = { - input: "dist-esm/keyvault-admin/src/index.js", + input: "dist-esm/src/index.js", output: { file: "dist-browser/azure-keyvault-admin.js", banner: banner, diff --git a/sdk/keyvault/keyvault-certificates/api-extractor.json b/sdk/keyvault/keyvault-certificates/api-extractor.json index d4a560a85614..011525a544b4 100644 --- a/sdk/keyvault/keyvault-certificates/api-extractor.json +++ b/sdk/keyvault/keyvault-certificates/api-extractor.json @@ -1,6 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "types/keyvault-certificates/src/index.d.ts", + "mainEntryPointFilePath": "types/src/index.d.ts", "docModel": { "enabled": true }, diff --git a/sdk/keyvault/keyvault-certificates/rollup.base.config.js b/sdk/keyvault/keyvault-certificates/rollup.base.config.js index d84228da1505..d3ed605f4ac6 100644 --- a/sdk/keyvault/keyvault-certificates/rollup.base.config.js +++ b/sdk/keyvault/keyvault-certificates/rollup.base.config.js @@ -33,7 +33,7 @@ export function nodeConfig(test = false) { const externalNodeBuiltins = ["crypto", "fs", "os", "url", "assert"]; const additionalExternals = ["keytar"]; const baseConfig = { - input: "dist-esm/keyvault-certificates/src/index.js", + input: "dist-esm/src/index.js", external: depNames.concat(externalNodeBuiltins, additionalExternals), output: { file: "dist/index.js", @@ -81,7 +81,7 @@ export function nodeConfig(test = false) { export function browserConfig(test = false) { const baseConfig = { - input: "dist-esm/keyvault-certificates/src/index.js", + input: "dist-esm/src/index.js", output: { file: "dist-browser/azure-keyvault-certificates.js", banner: banner, diff --git a/sdk/keyvault/keyvault-keys/api-extractor.json b/sdk/keyvault/keyvault-keys/api-extractor.json index 3afc3e69a5ea..24dc512f9c4c 100644 --- a/sdk/keyvault/keyvault-keys/api-extractor.json +++ b/sdk/keyvault/keyvault-keys/api-extractor.json @@ -1,6 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "types/keyvault-keys/src/index.d.ts", + "mainEntryPointFilePath": "types/src/index.d.ts", "docModel": { "enabled": true }, diff --git a/sdk/keyvault/keyvault-keys/rollup.base.config.js b/sdk/keyvault/keyvault-keys/rollup.base.config.js index d5837c4243ed..a075171c57f1 100644 --- a/sdk/keyvault/keyvault-keys/rollup.base.config.js +++ b/sdk/keyvault/keyvault-keys/rollup.base.config.js @@ -33,7 +33,7 @@ export function nodeConfig(test = false) { const externalNodeBuiltins = ["crypto", "fs", "os", "url", "assert", "chai", "constants"]; const additionalExternals = ["keytar"]; const baseConfig = { - input: "dist-esm/keyvault-keys/src/index.js", + input: "dist-esm/src/index.js", external: depNames.concat(externalNodeBuiltins, additionalExternals), output: { file: "dist/index.js", @@ -81,7 +81,7 @@ export function nodeConfig(test = false) { export function browserConfig(test = false) { const baseConfig = { - input: "dist-esm/keyvault-keys/src/index.js", + input: "dist-esm/src/index.js", output: { file: "dist-browser/azure-keyvault-keys.js", banner: banner, diff --git a/sdk/keyvault/keyvault-secrets/api-extractor.json b/sdk/keyvault/keyvault-secrets/api-extractor.json index 3ae6cbeedc67..7a4d1e7f8cfb 100644 --- a/sdk/keyvault/keyvault-secrets/api-extractor.json +++ b/sdk/keyvault/keyvault-secrets/api-extractor.json @@ -1,6 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "types/keyvault-secrets/src/index.d.ts", + "mainEntryPointFilePath": "types/src/index.d.ts", "docModel": { "enabled": true }, diff --git a/sdk/keyvault/keyvault-secrets/rollup.base.config.js b/sdk/keyvault/keyvault-secrets/rollup.base.config.js index b5b8bc2d925f..2c1093850379 100644 --- a/sdk/keyvault/keyvault-secrets/rollup.base.config.js +++ b/sdk/keyvault/keyvault-secrets/rollup.base.config.js @@ -33,7 +33,7 @@ export function nodeConfig(test = false) { const externalNodeBuiltins = ["crypto", "fs", "os", "url", "assert"]; const additionalExternals = ["keytar"]; const baseConfig = { - input: "dist-esm/keyvault-secrets/src/index.js", + input: "dist-esm/src/index.js", external: depNames.concat(externalNodeBuiltins, additionalExternals), output: { file: "dist/index.js", @@ -81,7 +81,7 @@ export function nodeConfig(test = false) { export function browserConfig(test = false) { const baseConfig = { - input: "dist-esm/keyvault-secrets/src/index.js", + input: "dist-esm/src/index.js", output: { file: "dist-browser/azure-keyvault-secrets.js", banner: banner, From 2c27e20e072519dd3371e7c09db5be8a2ce8c170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez?= Date: Mon, 14 Sep 2020 17:25:47 -0400 Subject: [PATCH 05/10] Fixing paths after removing keyvault-common --- sdk/keyvault/keyvault-admin/package.json | 4 ++-- sdk/keyvault/keyvault-admin/test/internal/userAgent.spec.ts | 2 +- sdk/keyvault/keyvault-certificates/package.json | 6 +++--- .../keyvault-certificates/test/internal/userAgent.spec.ts | 4 ++-- sdk/keyvault/keyvault-keys/package.json | 6 +++--- sdk/keyvault/keyvault-keys/test/internal/userAgent.spec.ts | 4 ++-- sdk/keyvault/keyvault-secrets/package.json | 6 +++--- .../keyvault-secrets/test/internal/userAgent.spec.ts | 4 ++-- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/sdk/keyvault/keyvault-admin/package.json b/sdk/keyvault/keyvault-admin/package.json index 2586e4c88eed..8e45e6620ce5 100644 --- a/sdk/keyvault/keyvault-admin/package.json +++ b/sdk/keyvault/keyvault-admin/package.json @@ -24,7 +24,7 @@ "url": "https://github.com/Azure/azure-sdk-for-js/issues" }, "main": "./dist/index.js", - "module": "dist-esm/keyvault-admin/src/index.js", + "module": "dist-esm/index.js", "types": "./types/keyvault-admin.d.ts", "engine": { "node": ">=8.0.0" @@ -36,7 +36,7 @@ "types/keyvault-admin.d.ts", "dist/", "dist-browser/", - "dist-esm/keyvault-admin/src", + "dist-esm/", "README.md", "LICENSE" ], diff --git a/sdk/keyvault/keyvault-admin/test/internal/userAgent.spec.ts b/sdk/keyvault/keyvault-admin/test/internal/userAgent.spec.ts index 548e5ddddde1..b3feb728fd3b 100644 --- a/sdk/keyvault/keyvault-admin/test/internal/userAgent.spec.ts +++ b/sdk/keyvault/keyvault-admin/test/internal/userAgent.spec.ts @@ -26,7 +26,7 @@ describe("Secrets Admin's user agent (only in Node, because of fs)", () => { version = fileContents.version; } catch { const fileContents = JSON.parse( - fs.readFileSync(path.join(__dirname, "../../../../package.json"), { encoding: "utf-8" }) + fs.readFileSync(path.join(__dirname, "../../../package.json"), { encoding: "utf-8" }) ); version = fileContents.version; } diff --git a/sdk/keyvault/keyvault-certificates/package.json b/sdk/keyvault/keyvault-certificates/package.json index 0ec881a68bf6..e576c7411b59 100644 --- a/sdk/keyvault/keyvault-certificates/package.json +++ b/sdk/keyvault/keyvault-certificates/package.json @@ -20,7 +20,7 @@ "url": "https://github.com/Azure/azure-sdk-for-js/issues" }, "main": "./dist/index.js", - "module": "dist-esm/keyvault-certificates/src/index.js", + "module": "dist-esm/src/index.js", "types": "./types/keyvault-certificates.d.ts", "engines": { "node": ">=8.0.0" @@ -29,7 +29,7 @@ "types/keyvault-certificates.d.ts", "dist/", "dist-browser/", - "dist-esm/keyvault-certificates/src", + "dist-esm/src", "README.md", "LICENSE" ], @@ -47,7 +47,7 @@ "build": "npm run extract-api && npm run build:es6 && npm run build:nodebrowser", "check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "clean": "rimraf dist-esm dist-test typings *.tgz *.log samples/typescript/dist", - "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/dist/keyvault-certificates/dist-samples/typescript/src/", + "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/src/", "extract-api": "tsc -p . && api-extractor run --local", "format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"samples/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "integration-test:browser": "karma start --single-run", diff --git a/sdk/keyvault/keyvault-certificates/test/internal/userAgent.spec.ts b/sdk/keyvault/keyvault-certificates/test/internal/userAgent.spec.ts index c34201cdd647..dddff387c703 100644 --- a/sdk/keyvault/keyvault-certificates/test/internal/userAgent.spec.ts +++ b/sdk/keyvault/keyvault-certificates/test/internal/userAgent.spec.ts @@ -27,9 +27,9 @@ describe("Certificates client's user agent (only in Node, because of fs)", () => version = fileContents.version; } catch { // The integration-test script has this test file in a considerably different place, - // Along the lines of: dist-esm/keyvault-keys/test/internal/userAgent.spec.ts + // Along the lines of: dist-esm/test/internal/userAgent.spec.ts const fileContents = JSON.parse( - fs.readFileSync(path.join(__dirname, "../../../../package.json"), { encoding: "utf-8" }) + fs.readFileSync(path.join(__dirname, "../../../package.json"), { encoding: "utf-8" }) ); version = fileContents.version; } diff --git a/sdk/keyvault/keyvault-keys/package.json b/sdk/keyvault/keyvault-keys/package.json index c38b3e15de5d..0cad326473e2 100644 --- a/sdk/keyvault/keyvault-keys/package.json +++ b/sdk/keyvault/keyvault-keys/package.json @@ -20,7 +20,7 @@ "url": "https://github.com/Azure/azure-sdk-for-js/issues" }, "main": "./dist/index.js", - "module": "dist-esm/keyvault-keys/src/index.js", + "module": "dist-esm/src/index.js", "types": "./types/keyvault-keys.d.ts", "engines": { "node": ">=8.0.0" @@ -29,7 +29,7 @@ "types/keyvault-keys.d.ts", "dist/", "dist-browser/", - "dist-esm/keyvault-keys/src", + "dist-esm/src", "README.md", "LICENSE" ], @@ -47,7 +47,7 @@ "build": "npm run extract-api && npm run build:es6 && npm run build:nodebrowser", "check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "clean": "rimraf dist dist-esm dist-test types *.tgz *.log dist-browser statistics.html coverage && rimraf src/**/*.js && rimraf test/**/*.js", - "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/dist/keyvault-keys/dist-samples/typescript/src/", + "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/src/", "extract-api": "tsc -p . && api-extractor run --local", "format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "integration-test:browser": "karma start --single-run", diff --git a/sdk/keyvault/keyvault-keys/test/internal/userAgent.spec.ts b/sdk/keyvault/keyvault-keys/test/internal/userAgent.spec.ts index 736f5ba1b513..3b533a5d12a9 100644 --- a/sdk/keyvault/keyvault-keys/test/internal/userAgent.spec.ts +++ b/sdk/keyvault/keyvault-keys/test/internal/userAgent.spec.ts @@ -27,9 +27,9 @@ describe("Keys client's user agent (only in Node, because of fs)", () => { version = fileContents.version; } catch { // The integration-test script has this test file in a considerably different place, - // Along the lines of: dist-esm/keyvault-keys/test/internal/userAgent.spec.ts + // Along the lines of: dist-esm/test/internal/userAgent.spec.ts const fileContents = JSON.parse( - fs.readFileSync(path.join(__dirname, "../../../../package.json"), { encoding: "utf-8" }) + fs.readFileSync(path.join(__dirname, "../../../package.json"), { encoding: "utf-8" }) ); version = fileContents.version; } diff --git a/sdk/keyvault/keyvault-secrets/package.json b/sdk/keyvault/keyvault-secrets/package.json index e44ec4d410b6..2a02f99de14f 100644 --- a/sdk/keyvault/keyvault-secrets/package.json +++ b/sdk/keyvault/keyvault-secrets/package.json @@ -20,7 +20,7 @@ "url": "https://github.com/Azure/azure-sdk-for-js/issues" }, "main": "./dist/index.js", - "module": "dist-esm/keyvault-secrets/src/index.js", + "module": "dist-esm/index.js", "types": "./types/keyvault-secrets.d.ts", "engine": { "node": ">=8.0.0" @@ -32,7 +32,7 @@ "types/keyvault-secrets.d.ts", "dist/", "dist-browser/", - "dist-esm/keyvault-secrets/src", + "dist-esm/", "README.md", "LICENSE" ], @@ -50,7 +50,7 @@ "build": "npm run extract-api && npm run build:es6 && npm run build:nodebrowser", "check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "clean": "rimraf dist dist-esm dist-test types *.tgz *.log dist-browser statistics.html coverage && rimraf src/**/*.js && rimraf test/**/*.js", - "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/dist/keyvault-secrets/dist-samples/typescript/src/", + "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/src/", "extract-api": "tsc -p . && api-extractor run --local", "format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "integration-test:browser": "karma start --single-run", diff --git a/sdk/keyvault/keyvault-secrets/test/internal/userAgent.spec.ts b/sdk/keyvault/keyvault-secrets/test/internal/userAgent.spec.ts index f46c1761960b..b882feb74f4e 100644 --- a/sdk/keyvault/keyvault-secrets/test/internal/userAgent.spec.ts +++ b/sdk/keyvault/keyvault-secrets/test/internal/userAgent.spec.ts @@ -27,9 +27,9 @@ describe("Secrets client's user agent (only in Node, because of fs)", () => { version = fileContents.version; } catch { // The integration-test script has this test file in a considerably different place, - // Along the lines of: dist-esm/keyvault-keys/test/internal/userAgent.spec.ts + // Along the lines of: dist-esm/test/internal/userAgent.spec.ts const fileContents = JSON.parse( - fs.readFileSync(path.join(__dirname, "../../../../package.json"), { encoding: "utf-8" }) + fs.readFileSync(path.join(__dirname, "../../../package.json"), { encoding: "utf-8" }) ); version = fileContents.version; } From b73d63550d118cb56f49a78662c3e77a25d53cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez?= Date: Mon, 14 Sep 2020 19:06:14 -0400 Subject: [PATCH 06/10] fixed bad dist-esm index.js references --- sdk/keyvault/keyvault-admin/package.json | 2 +- sdk/keyvault/keyvault-secrets/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/keyvault/keyvault-admin/package.json b/sdk/keyvault/keyvault-admin/package.json index 8e45e6620ce5..233130a96c64 100644 --- a/sdk/keyvault/keyvault-admin/package.json +++ b/sdk/keyvault/keyvault-admin/package.json @@ -24,7 +24,7 @@ "url": "https://github.com/Azure/azure-sdk-for-js/issues" }, "main": "./dist/index.js", - "module": "dist-esm/index.js", + "module": "dist-esm/src/index.js", "types": "./types/keyvault-admin.d.ts", "engine": { "node": ">=8.0.0" diff --git a/sdk/keyvault/keyvault-secrets/package.json b/sdk/keyvault/keyvault-secrets/package.json index 2a02f99de14f..395962f84369 100644 --- a/sdk/keyvault/keyvault-secrets/package.json +++ b/sdk/keyvault/keyvault-secrets/package.json @@ -20,7 +20,7 @@ "url": "https://github.com/Azure/azure-sdk-for-js/issues" }, "main": "./dist/index.js", - "module": "dist-esm/index.js", + "module": "dist-esm/src/index.js", "types": "./types/keyvault-secrets.d.ts", "engine": { "node": ">=8.0.0" From ff22856c0f29d9d925b4700393470fa155dcfc78 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 16 Sep 2020 08:00:37 +1200 Subject: [PATCH 07/10] Update paths --- common/config/rush/common-versions.json | 5 ++++- sdk/keyvault/keyvault-admin/package.json | 2 +- sdk/keyvault/keyvault-certificates/package.json | 2 +- sdk/keyvault/keyvault-keys/package.json | 2 +- sdk/keyvault/keyvault-secrets/package.json | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/common/config/rush/common-versions.json b/common/config/rush/common-versions.json index e15efa4016c2..3bc60046e271 100644 --- a/common/config/rush/common-versions.json +++ b/common/config/rush/common-versions.json @@ -54,6 +54,9 @@ // Monitor: Allow node 10 types until Timeout / Timer conflict is resolved in OpenTelemetry repo // TODO: remove when released https://github.com/open-telemetry/opentelemetry-js/pull/1352 - "@types/node": ["^10.0.0"] + "@types/node": ["^10.0.0"], + + // Moved challenged-based auth to core-http, but not yet bumping all packages to new dependency + "@azure/core-http": ["^1.1.9"] } } diff --git a/sdk/keyvault/keyvault-admin/package.json b/sdk/keyvault/keyvault-admin/package.json index 2586e4c88eed..5830d798ed3c 100644 --- a/sdk/keyvault/keyvault-admin/package.json +++ b/sdk/keyvault/keyvault-admin/package.json @@ -78,7 +78,7 @@ "sideEffects": false, "dependencies": { "@azure/abort-controller": "^1.0.0", - "@azure/core-http": "^1.1.6", + "@azure/core-http": "^1.1.9", "@azure/core-lro": "^1.0.2", "@azure/core-paging": "^1.1.1", "@azure/core-tracing": "1.0.0-preview.9", diff --git a/sdk/keyvault/keyvault-certificates/package.json b/sdk/keyvault/keyvault-certificates/package.json index 0ec881a68bf6..cb6ed66fa300 100644 --- a/sdk/keyvault/keyvault-certificates/package.json +++ b/sdk/keyvault/keyvault-certificates/package.json @@ -91,7 +91,7 @@ }, "dependencies": { "@azure/abort-controller": "^1.0.0", - "@azure/core-http": "^1.1.6", + "@azure/core-http": "^1.1.9", "@azure/core-lro": "^1.0.2", "@azure/core-paging": "^1.1.1", "@azure/core-tracing": "1.0.0-preview.9", diff --git a/sdk/keyvault/keyvault-keys/package.json b/sdk/keyvault/keyvault-keys/package.json index c38b3e15de5d..5f20685034bc 100644 --- a/sdk/keyvault/keyvault-keys/package.json +++ b/sdk/keyvault/keyvault-keys/package.json @@ -81,7 +81,7 @@ ] }, "dependencies": { - "@azure/core-http": "^1.1.6", + "@azure/core-http": "^1.1.9", "@azure/core-lro": "^1.0.2", "@azure/core-paging": "^1.1.1", "@azure/core-tracing": "1.0.0-preview.9", diff --git a/sdk/keyvault/keyvault-secrets/package.json b/sdk/keyvault/keyvault-secrets/package.json index e44ec4d410b6..d4e7ae4c91cc 100644 --- a/sdk/keyvault/keyvault-secrets/package.json +++ b/sdk/keyvault/keyvault-secrets/package.json @@ -90,7 +90,7 @@ }, "dependencies": { "@azure/abort-controller": "^1.0.0", - "@azure/core-http": "^1.1.6", + "@azure/core-http": "^1.1.9", "@azure/core-lro": "^1.0.2", "@azure/core-paging": "^1.1.1", "@azure/core-tracing": "1.0.0-preview.9", From d54478c993d20d2859cabf0ef5d1d267689cb890 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 16 Sep 2020 10:33:41 +1200 Subject: [PATCH 08/10] Update docs --- sdk/core/core-http/review/core-http.api.md | 2 -- .../policies/challengeBasedAuthenticationPolicy.ts | 12 ++++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sdk/core/core-http/review/core-http.api.md b/sdk/core/core-http/review/core-http.api.md index 9dc405a98d4b..461794925c79 100644 --- a/sdk/core/core-http/review/core-http.api.md +++ b/sdk/core/core-http/review/core-http.api.md @@ -61,9 +61,7 @@ export class AuthenticationChallenge { // @public export class AuthenticationChallengeCache { - // (undocumented) challenge?: AuthenticationChallenge; - // (undocumented) setCachedChallenge(challenge: AuthenticationChallenge): void; } diff --git a/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts b/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts index 69f84b22d890..e745c110bd79 100644 --- a/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts +++ b/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts @@ -30,6 +30,11 @@ type ParsedWWWAuthenticate = { * Representation of the Authentication Challenge */ export class AuthenticationChallenge { + /** + * Internal representation of an authentication challenge + * @param authorization The authorization of the challenge + * @param scope The scope to allow authentication + */ constructor(public authorization: string, public scope: string) {} /** @@ -52,8 +57,15 @@ export class AuthenticationChallenge { * so that we can compare on any further request. */ export class AuthenticationChallengeCache { + /** + * The previously used challenge, if available + */ public challenge?: AuthenticationChallenge; + /** + * Sets the cached challenge + * @param challenge the challenge that is to be cached + */ public setCachedChallenge(challenge: AuthenticationChallenge) { this.challenge = challenge; } From b88a6a5aef9788a32adf22d24c48e0f107e7a54b Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 18 Sep 2020 07:53:00 +1200 Subject: [PATCH 09/10] Add mock tests --- sdk/core/core-http/review/core-http.api.md | 26 --- .../challengeBasedAuthenticationPolicy.ts | 7 +- ...challengeBasedAuthenticationPolicyTests.ts | 194 ++++++++++++++++++ 3 files changed, 196 insertions(+), 31 deletions(-) create mode 100644 sdk/core/core-http/test/policies/challengeBasedAuthenticationPolicyTests.ts diff --git a/sdk/core/core-http/review/core-http.api.md b/sdk/core/core-http/review/core-http.api.md index 4b17be95ac6a..33b70e7795e0 100644 --- a/sdk/core/core-http/review/core-http.api.md +++ b/sdk/core/core-http/review/core-http.api.md @@ -49,22 +49,6 @@ export class ApiKeyCredentials implements ServiceClientCredentials { // @public export function applyMixins(targetCtor: any, sourceCtors: any[]): void; -// @public -export class AuthenticationChallenge { - constructor(authorization: string, scope: string); - // (undocumented) - authorization: string; - equalTo(other: AuthenticationChallenge | undefined): boolean; - // (undocumented) - scope: string; -} - -// @public -export class AuthenticationChallengeCache { - challenge?: AuthenticationChallenge; - setCachedChallenge(challenge: AuthenticationChallenge): void; -} - // @public (undocumented) export type Authenticator = (challenge: object) => Promise; @@ -538,16 +522,6 @@ export interface ParameterValue { value: any; } -// Warning: (ae-forgotten-export) The symbol "ValidParsedWWWAuthenticateProperties" needs to be exported by the entry point coreHttp.d.ts -// -// @public -export type ParsedWWWAuthenticate = { - [Key in ValidParsedWWWAuthenticateProperties]?: string; -}; - -// @public -export function parseWWWAuthenticate(wwwAuthenticate: string): ParsedWWWAuthenticate; - // @public export function parseXML(str: string, opts?: { includeRoot?: boolean; diff --git a/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts b/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts index 5371ebf3394e..512948058bc8 100644 --- a/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts +++ b/sdk/core/core-http/src/policies/challengeBasedAuthenticationPolicy.ts @@ -22,10 +22,7 @@ type ValidParsedWWWAuthenticateProperties = | "resource" | "scope"; -/** - * A mapping from properties to values - */ -export type ParsedWWWAuthenticate = { +type ParsedWWWAuthenticate = { [Key in ValidParsedWWWAuthenticateProperties]?: string; }; @@ -200,7 +197,7 @@ export class ChallengeBasedAuthenticationPolicy extends BaseRequestPolicy { const challenge = new AuthenticationChallenge(authorization, resource + "/.default"); - // Either if there's no cached challenge at this point (could have happen in parallel), + // Either if there's no cached challenge at this point (could have happened in parallel), // or if the cached challenge has a different scope, // we store the just received challenge and reset the cached token, to force a re-authentication. if (!this.challengeCache.challenge?.equalTo(challenge)) { diff --git a/sdk/core/core-http/test/policies/challengeBasedAuthenticationPolicyTests.ts b/sdk/core/core-http/test/policies/challengeBasedAuthenticationPolicyTests.ts new file mode 100644 index 000000000000..173709d6ae57 --- /dev/null +++ b/sdk/core/core-http/test/policies/challengeBasedAuthenticationPolicyTests.ts @@ -0,0 +1,194 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { assert } from "chai"; +import { fake, createSandbox } from "sinon"; +// import { env, Recorder } from "@azure/test-utils-recorder"; +import { OperationSpec } from "../../src/operationSpec"; +import { WebResource } from "../../src/webResource"; +import { HttpHeaders } from "../../src/httpHeaders"; +import { RequestPolicy, RequestPolicyOptions } from "../../src/policies/requestPolicy"; +import { HttpOperationResponse } from "../../src/httpOperationResponse"; +import { + ExpiringAccessTokenCache, +} from "../../src/credentials/accessTokenCache"; + +import { + AuthenticationChallengeCache, + AuthenticationChallenge, + parseWWWAuthenticate, ChallengeBasedAuthenticationPolicy + +} from "../../src/policies/challengeBasedAuthenticationPolicy"; + +import { TokenCredential } from "@azure/core-auth"; + +// import { authenticate } from "../utils/testAuthentication"; +// import TestClient from "../utils/testClient"; + +// Following the philosophy of not testing the insides if we can test the outsides... +// I present you with this "Get Out of Jail Free" card (in reference to Monopoly). +// Once we move to a common folder, and after some refactoring, +// we will be able to unit test the insides in detail. + +describe("Challenge based authentication tests", () => { + const mockPolicy: RequestPolicy = { + sendRequest(request: WebResource): Promise { + let headers = new HttpHeaders(); + headers.set("WWW-Authenticate", `Bearer authorization="some_authorization", resource="https://some.url"`); + return Promise.resolve({ + request: request, + status: 401, + headers + }); + } + }; + + function createChallengeTokenPolicy( + credential: TokenCredential + ): ChallengeBasedAuthenticationPolicy { + return new ChallengeBasedAuthenticationPolicy( + mockPolicy, + new RequestPolicyOptions(), + credential, + new ExpiringAccessTokenCache(), + new AuthenticationChallengeCache(), + ); + } + + beforeEach(async function() { + // const authentication = await authenticate(this); + // keySuffix = authentication.keySuffix; + // client = authentication.client; + // testClient = authentication.testClient; + // recorder = authentication.recorder; + }); + + afterEach(async function() { + // await recorder.stop(); + }); + + // The tests follow + + it("Once authenticated, new requests should not authenticate again", async function() { + // Our goal is to intercept how our pipelines are storing the challenge. + // The first network call should indeed set the challenge in memory. + // Subsequent network calls should not set new challenges. + + const sandbox = createSandbox(); + const spy = sandbox.spy(AuthenticationChallengeCache.prototype, "setCachedChallenge"); + + const mockToken = "token"; + const fakeGetToken = fake.returns(Promise.resolve({ token: mockToken, expiresOn: new Date() })); + const mockCredential: TokenCredential = { + getToken: fakeGetToken + }; + + const challengeTokenPolicy = createChallengeTokenPolicy(mockCredential); + + // Now we run what would be a normal use of the client. + // Here we will create two keys, then flush them. + // testClient.flushKey deletes, then purges the keys. + for (let i = 0; i < 10; ++i) { + const request = createRequest(); + await challengeTokenPolicy.sendRequest(request); + } + + // The challenge should have been written to the cache exactly ONCE. + assert.equal(spy.getCalls().length, 1); + + // Back to normal. + sandbox.restore(); + + // Note: Failing to authenticate will make network requests throw. + function createRequest(operationSpec?: OperationSpec): WebResource { + const request = new WebResource("https://test"); + request.operationSpec = operationSpec; + return request; + } + }); + + it("Authentication should work for parallel requests", async function() { + const sandbox = createSandbox(); + const spy = sandbox.spy(AuthenticationChallengeCache.prototype, "setCachedChallenge"); + const spyEqualTo = sandbox.spy(AuthenticationChallenge.prototype, "equalTo"); + + const mockToken = "token"; + const fakeGetToken = fake.returns(Promise.resolve({ token: mockToken, expiresOn: new Date() })); + const mockCredential: TokenCredential = { + getToken: fakeGetToken + }; + + const challengeTokenPolicy = createChallengeTokenPolicy(mockCredential); + + let promises = []; + + // Now we run what would be a normal use of the client. + // Here we will create two keys, then flush them. + // testClient.flushKey deletes, then purges the keys. + for (let i = 0; i < 10; ++i) { + const request = createRequest(); + promises.push(challengeTokenPolicy.sendRequest(request)); + } + + for (let i = 0; i < 10; ++i) { + await promises[i]; + } + + // The challenge should have been written to the cache exactly ONCE. + assert.equal(spy.getCalls().length, 1); + // Even though we had parallel requests, only one authentication should have happened. + + // This is determined by the comparison between the cached challenge and the new receive challenge. + // So, AuthenticationChallenge's equalTo should have returned true at least once. + assert.ok(spyEqualTo.returned(true)); + + // The challenge should have been written to the cache exactly ONCE. + assert.equal(spy.getCalls().length, 1); + + // Back to normal. + sandbox.restore(); + + // Note: Failing to authenticate will make network requests throw. + function createRequest(operationSpec?: OperationSpec): WebResource { + const request = new WebResource("https://test"); + request.operationSpec = operationSpec; + return request; + } + }); + + describe("parseWWWAuthenticate tests", () => { + it("Should work for known shapes of the WWW-Authenticate header", () => { + const wwwAuthenticate1 = `Bearer authorization="some_authorization", resource="https://some.url"`; + const parsed1 = parseWWWAuthenticate(wwwAuthenticate1); + assert.deepEqual(parsed1, { + authorization: "some_authorization", + resource: "https://some.url" + }); + + const wwwAuthenticate2 = `Bearer authorization="some_authorization", scope="https://some.url"`; + const parsed2 = parseWWWAuthenticate(wwwAuthenticate2); + assert.deepEqual(parsed2, { + authorization: "some_authorization", + scope: "https://some.url" + }); + }); + + it("Should skip unexpected properties on the WWW-Authenticate header", () => { + const wwwAuthenticate1 = `Bearer authorization="some_authorization", a="a", b="b"`; + const parsed1 = parseWWWAuthenticate(wwwAuthenticate1); + assert.deepEqual(parsed1 as any, { + authorization: "some_authorization", + a: "a", + b: "b" + }); + + const wwwAuthenticate2 = `scope="https://some.url", a="a", c="c"`; + const parsed2 = parseWWWAuthenticate(wwwAuthenticate2); + assert.deepEqual(parsed2 as any, { + scope: "https://some.url", + a: "a", + c: "c" + }); + }); + }); +}); From 4ae98bd2ac10e00b5ba9f9754910e634fdbcd620 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 18 Sep 2020 08:58:58 +1200 Subject: [PATCH 10/10] Add mock tests --- .../challengeBasedAuthenticationPolicyTests.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sdk/core/core-http/test/policies/challengeBasedAuthenticationPolicyTests.ts b/sdk/core/core-http/test/policies/challengeBasedAuthenticationPolicyTests.ts index 173709d6ae57..12b50b06b5b3 100644 --- a/sdk/core/core-http/test/policies/challengeBasedAuthenticationPolicyTests.ts +++ b/sdk/core/core-http/test/policies/challengeBasedAuthenticationPolicyTests.ts @@ -9,15 +9,13 @@ import { WebResource } from "../../src/webResource"; import { HttpHeaders } from "../../src/httpHeaders"; import { RequestPolicy, RequestPolicyOptions } from "../../src/policies/requestPolicy"; import { HttpOperationResponse } from "../../src/httpOperationResponse"; -import { - ExpiringAccessTokenCache, -} from "../../src/credentials/accessTokenCache"; +import { ExpiringAccessTokenCache } from "../../src/credentials/accessTokenCache"; import { AuthenticationChallengeCache, AuthenticationChallenge, - parseWWWAuthenticate, ChallengeBasedAuthenticationPolicy - + parseWWWAuthenticate, + ChallengeBasedAuthenticationPolicy } from "../../src/policies/challengeBasedAuthenticationPolicy"; import { TokenCredential } from "@azure/core-auth"; @@ -34,7 +32,10 @@ describe("Challenge based authentication tests", () => { const mockPolicy: RequestPolicy = { sendRequest(request: WebResource): Promise { let headers = new HttpHeaders(); - headers.set("WWW-Authenticate", `Bearer authorization="some_authorization", resource="https://some.url"`); + headers.set( + "WWW-Authenticate", + `Bearer authorization="some_authorization", resource="https://some.url"` + ); return Promise.resolve({ request: request, status: 401, @@ -51,7 +52,7 @@ describe("Challenge based authentication tests", () => { new RequestPolicyOptions(), credential, new ExpiringAccessTokenCache(), - new AuthenticationChallengeCache(), + new AuthenticationChallengeCache() ); }