botframework-connector
Version:
Bot Connector is autorest generated connector client.
170 lines • 10.6 kB
JavaScript
;
/**
* @module botframework-connector
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EmulatorValidation = void 0;
/* eslint-disable @typescript-eslint/no-namespace */
const jsonwebtoken_1 = require("jsonwebtoken");
const authenticationConstants_1 = require("./authenticationConstants");
const authenticationConfiguration_1 = require("./authenticationConfiguration");
const governmentConstants_1 = require("./governmentConstants");
const jwtTokenExtractor_1 = require("./jwtTokenExtractor");
const jwtTokenValidation_1 = require("./jwtTokenValidation");
const authenticationError_1 = require("./authenticationError");
const botframework_schema_1 = require("botframework-schema");
const tokenValidationParameters_1 = require("./tokenValidationParameters");
/**
* @deprecated Use `ConfigurationBotFrameworkAuthentication` instead to perform emulator validation.
* Validates and Examines JWT tokens from the Bot Framework Emulator
*/
var EmulatorValidation;
(function (EmulatorValidation) {
/**
* TO BOT FROM EMULATOR: Token validation parameters when connecting to a channel.
*/
EmulatorValidation.ToBotFromEmulatorTokenValidationParameters = tokenValidationParameters_1.ToBotFromBotOrEmulatorTokenValidationParameters;
/**
* Determines if a given Auth header is from the Bot Framework Emulator
*
* @param {string} authHeader Bearer Token, in the "Bearer [Long String]" Format.
* @returns {boolean} True, if the token was issued by the Emulator. Otherwise, false.
*/
function isTokenFromEmulator(authHeader) {
var _a;
// The Auth Header generally looks like this:
// "Bearer eyJ0e[...Big Long String...]XAiO"
if (!authHeader) {
// No token. Can't be an emulator token.
return false;
}
const parts = authHeader.split(' ');
if (parts.length !== 2) {
// Emulator tokens MUST have exactly 2 parts. If we don't have 2 parts, it's not an emulator token
return false;
}
const authScheme = parts[0];
const bearerToken = parts[1];
// We now have an array that should be:
// [0] = "Bearer"
// [1] = "[Big Long String]"
if (authScheme !== 'Bearer') {
// The scheme from the emulator MUST be "Bearer"
return false;
}
// Parse the Big Long String into an actual token.
const token = (0, jsonwebtoken_1.decode)(bearerToken, { complete: true });
if (!token) {
return false;
}
// Is there an Issuer?
const issuer = token.payload[authenticationConstants_1.AuthenticationConstants.IssuerClaim];
if (!issuer) {
// No Issuer, means it's not from the Emulator.
return false;
}
const validTokenIssuers = tokenValidationParameters_1.ToBotFromBotOrEmulatorTokenValidationParameters.issuer;
//Validation to manage the issuer object as a string.
if (Array.isArray(validTokenIssuers)) {
const tenantId = (_a = token === null || token === void 0 ? void 0 : token.payload[authenticationConstants_1.AuthenticationConstants.TenantIdClaim]) !== null && _a !== void 0 ? _a : '';
//Validate if there is an existing issuer with the same tid value.
if (tenantId != '' && validTokenIssuers.find((issuer) => issuer.includes(tenantId)) == null) {
//If the issuer doesn't exist, this is added using the Emulator token issuer structure.
//This allows use of the SingleTenant authentication through Emulator.
validTokenIssuers.push(`${authenticationConstants_1.AuthenticationConstants.ValidTokenIssuerUrlTemplateV1}${tenantId}/`);
validTokenIssuers.push(`${authenticationConstants_1.AuthenticationConstants.ValidTokenIssuerUrlTemplateV2}${tenantId}/v2.0`);
validTokenIssuers.push(`${authenticationConstants_1.AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV1}${tenantId}/`);
validTokenIssuers.push(`${authenticationConstants_1.AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV2}${tenantId}/v2.0`);
}
}
// Is the token issues by a source we consider to be the emulator?
if (validTokenIssuers && validTokenIssuers.indexOf(issuer) === -1) {
// Not a Valid Issuer. This is NOT a Bot Framework Emulator Token.
return false;
}
// The Token is from the Bot Framework Emulator. Success!
return true;
}
EmulatorValidation.isTokenFromEmulator = isTokenFromEmulator;
/**
* Validate the incoming Auth Header as a token sent from the Bot Framework Emulator.
* A token issued by the Bot Framework will FAIL this check. Only Emulator tokens will pass.
*
* @param {string} authHeader The raw HTTP header in the format: "Bearer [longString]"
* @param {ICredentialProvider} credentials The user defined set of valid credentials, such as the AppId.
* @param {string} channelService The channelService value that distinguishes public Azure from US Government Azure.
* @param {string} channelId The ID of the channel to validate.
* @param {AuthenticationConfiguration} authConfig The authentication configuration.
* @returns {Promise<ClaimsIdentity>} A valid ClaimsIdentity.
*/
function authenticateEmulatorToken(authHeader, credentials, channelService, channelId, authConfig = new authenticationConfiguration_1.AuthenticationConfiguration()) {
return __awaiter(this, void 0, void 0, function* () {
const openIdMetadataUrl = channelService !== undefined && jwtTokenValidation_1.JwtTokenValidation.isGovernment(channelService)
? governmentConstants_1.GovernmentConstants.ToBotFromEmulatorOpenIdMetadataUrl
: authenticationConstants_1.AuthenticationConstants.ToBotFromEmulatorOpenIdMetadataUrl;
const tokenExtractor = new jwtTokenExtractor_1.JwtTokenExtractor(EmulatorValidation.ToBotFromEmulatorTokenValidationParameters, openIdMetadataUrl, authenticationConstants_1.AuthenticationConstants.AllowedSigningAlgorithms);
const identity = yield tokenExtractor.getIdentityFromAuthHeader(authHeader, channelId, authConfig.requiredEndorsements);
if (!identity) {
// No valid identity. Not Authorized.
throw new authenticationError_1.AuthenticationError('Unauthorized. No valid identity.', botframework_schema_1.StatusCodes.UNAUTHORIZED);
}
if (!identity.isAuthenticated) {
// The token is in some way invalid. Not Authorized.
throw new authenticationError_1.AuthenticationError('Unauthorized. Is not authenticated', botframework_schema_1.StatusCodes.UNAUTHORIZED);
}
// Now check that the AppID in the claimset matches
// what we're looking for. Note that in a multi-tenant bot, this value
// comes from developer code that may be reaching out to a service, hence the
// Async validation.
const versionClaim = identity.getClaimValue(authenticationConstants_1.AuthenticationConstants.VersionClaim);
if (versionClaim === null) {
throw new authenticationError_1.AuthenticationError('Unauthorized. "ver" claim is required on Emulator Tokens.', botframework_schema_1.StatusCodes.UNAUTHORIZED);
}
let appId = '';
// The Emulator, depending on Version, sends the AppId via either the
// appid claim (Version 1) or the Authorized Party claim (Version 2).
if (!versionClaim || versionClaim === '1.0') {
// either no Version or a version of "1.0" means we should look for
// the claim in the "appid" claim.
const appIdClaim = identity.getClaimValue(authenticationConstants_1.AuthenticationConstants.AppIdClaim);
if (!appIdClaim) {
// No claim around AppID. Not Authorized.
throw new authenticationError_1.AuthenticationError('Unauthorized. "appid" claim is required on Emulator Token version "1.0".', botframework_schema_1.StatusCodes.UNAUTHORIZED);
}
appId = appIdClaim;
}
else if (versionClaim === '2.0') {
// Emulator, "2.0" puts the AppId in the "azp" claim.
const appZClaim = identity.getClaimValue(authenticationConstants_1.AuthenticationConstants.AuthorizedParty);
if (!appZClaim) {
// No claim around AppID. Not Authorized.
throw new authenticationError_1.AuthenticationError('Unauthorized. "azp" claim is required on Emulator Token version "2.0".', botframework_schema_1.StatusCodes.UNAUTHORIZED);
}
appId = appZClaim;
}
else {
// Unknown Version. Not Authorized.
throw new authenticationError_1.AuthenticationError(`Unauthorized. Unknown Emulator Token version "${versionClaim}".`, botframework_schema_1.StatusCodes.UNAUTHORIZED);
}
if (!(yield credentials.isValidAppId(appId))) {
throw new authenticationError_1.AuthenticationError(`Unauthorized. Invalid AppId passed on token: ${appId}`, botframework_schema_1.StatusCodes.UNAUTHORIZED);
}
return identity;
});
}
EmulatorValidation.authenticateEmulatorToken = authenticateEmulatorToken;
})(EmulatorValidation = exports.EmulatorValidation || (exports.EmulatorValidation = {}));
//# sourceMappingURL=emulatorValidation.js.map