@azure/core-rest-pipeline
Version:
Isomorphic client library for making HTTP requests in node.js and browser.
218 lines (217 loc) • 8.16 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var bearerTokenAuthenticationPolicy_exports = {};
__export(bearerTokenAuthenticationPolicy_exports, {
bearerTokenAuthenticationPolicy: () => bearerTokenAuthenticationPolicy,
bearerTokenAuthenticationPolicyName: () => bearerTokenAuthenticationPolicyName,
parseChallenges: () => parseChallenges
});
module.exports = __toCommonJS(bearerTokenAuthenticationPolicy_exports);
var import_tokenCycler = require("../util/tokenCycler.js");
var import_log = require("../log.js");
var import_restError = require("../restError.js");
const bearerTokenAuthenticationPolicyName = "bearerTokenAuthenticationPolicy";
async function trySendRequest(request, next) {
try {
return [await next(request), void 0];
} catch (e) {
if ((0, import_restError.isRestError)(e) && e.response) {
return [e.response, e];
} else {
throw e;
}
}
}
async function defaultAuthorizeRequest(options) {
const { scopes, getAccessToken, request } = options;
const getTokenOptions = {
abortSignal: request.abortSignal,
tracingOptions: request.tracingOptions,
enableCae: true
};
const accessToken = await getAccessToken(scopes, getTokenOptions);
if (accessToken) {
options.request.headers.set("Authorization", `Bearer ${accessToken.token}`);
}
}
function isChallengeResponse(response) {
return response.status === 401 && response.headers.has("WWW-Authenticate");
}
async function authorizeRequestOnCaeChallenge(onChallengeOptions, caeClaims) {
const { scopes } = onChallengeOptions;
const accessToken = await onChallengeOptions.getAccessToken(scopes, {
enableCae: true,
claims: caeClaims
});
if (!accessToken) {
return false;
}
onChallengeOptions.request.headers.set(
"Authorization",
`${accessToken.tokenType ?? "Bearer"} ${accessToken.token}`
);
return true;
}
function bearerTokenAuthenticationPolicy(options) {
const { credential, scopes, challengeCallbacks } = options;
const logger = options.logger || import_log.logger;
const callbacks = {
authorizeRequest: challengeCallbacks?.authorizeRequest?.bind(challengeCallbacks) ?? defaultAuthorizeRequest,
authorizeRequestOnChallenge: challengeCallbacks?.authorizeRequestOnChallenge?.bind(challengeCallbacks)
};
const getAccessToken = credential ? (0, import_tokenCycler.createTokenCycler)(
credential
/* , options */
) : () => Promise.resolve(null);
return {
name: bearerTokenAuthenticationPolicyName,
/**
* If there's no challenge parameter:
* - It will try to retrieve the token using the cache, or the credential's getToken.
* - Then it will try the next policy with or without the retrieved token.
*
* It uses the challenge parameters to:
* - Skip a first attempt to get the token from the credential if there's no cached token,
* since it expects the token to be retrievable only after the challenge.
* - Prepare the outgoing request if the `prepareRequest` method has been provided.
* - Send an initial request to receive the challenge if it fails.
* - Process a challenge if the response contains it.
* - Retrieve a token with the challenge information, then re-send the request.
*/
async sendRequest(request, next) {
if (!request.url.toLowerCase().startsWith("https://")) {
throw new Error(
"Bearer token authentication is not permitted for non-TLS protected (non-https) URLs."
);
}
await callbacks.authorizeRequest({
scopes: Array.isArray(scopes) ? scopes : [scopes],
request,
getAccessToken,
logger
});
let response;
let error;
let shouldSendRequest;
[response, error] = await trySendRequest(request, next);
if (isChallengeResponse(response)) {
let claims = getCaeChallengeClaims(response.headers.get("WWW-Authenticate"));
if (claims) {
let parsedClaim;
try {
parsedClaim = atob(claims);
} catch (e) {
logger.warning(
`The WWW-Authenticate header contains "claims" that cannot be parsed. Unable to perform the Continuous Access Evaluation authentication flow. Unparsable claims: ${claims}`
);
return response;
}
shouldSendRequest = await authorizeRequestOnCaeChallenge(
{
scopes: Array.isArray(scopes) ? scopes : [scopes],
response,
request,
getAccessToken,
logger
},
parsedClaim
);
if (shouldSendRequest) {
[response, error] = await trySendRequest(request, next);
}
} else if (callbacks.authorizeRequestOnChallenge) {
shouldSendRequest = await callbacks.authorizeRequestOnChallenge({
scopes: Array.isArray(scopes) ? scopes : [scopes],
request,
response,
getAccessToken,
logger
});
if (shouldSendRequest) {
[response, error] = await trySendRequest(request, next);
}
if (isChallengeResponse(response)) {
claims = getCaeChallengeClaims(response.headers.get("WWW-Authenticate") ?? "");
if (claims) {
let parsedClaim;
try {
parsedClaim = atob(claims);
} catch (e) {
logger.warning(
`The WWW-Authenticate header contains "claims" that cannot be parsed. Unable to perform the Continuous Access Evaluation authentication flow. Unparsable claims: ${claims}`
);
return response;
}
shouldSendRequest = await authorizeRequestOnCaeChallenge(
{
scopes: Array.isArray(scopes) ? scopes : [scopes],
response,
request,
getAccessToken,
logger
},
parsedClaim
);
if (shouldSendRequest) {
[response, error] = await trySendRequest(request, next);
}
}
}
}
}
if (error) {
throw error;
} else {
return response;
}
}
};
}
function parseChallenges(challenges) {
const challengeRegex = /(\w+)\s+((?:\w+=(?:"[^"]*"|[^,]*),?\s*)+)/g;
const paramRegex = /(\w+)="([^"]*)"/g;
const parsedChallenges = [];
let match;
while ((match = challengeRegex.exec(challenges)) !== null) {
const scheme = match[1];
const paramsString = match[2];
const params = {};
let paramMatch;
while ((paramMatch = paramRegex.exec(paramsString)) !== null) {
params[paramMatch[1]] = paramMatch[2];
}
parsedChallenges.push({ scheme, params });
}
return parsedChallenges;
}
function getCaeChallengeClaims(challenges) {
if (!challenges) {
return;
}
const parsedChallenges = parseChallenges(challenges);
return parsedChallenges.find(
(x) => x.scheme === "Bearer" && x.params.claims && x.params.error === "insufficient_claims"
)?.params.claims;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
bearerTokenAuthenticationPolicy,
bearerTokenAuthenticationPolicyName,
parseChallenges
});
//# sourceMappingURL=bearerTokenAuthenticationPolicy.js.map