138 lines
No EOL
8.1 KiB
JavaScript
138 lines
No EOL
8.1 KiB
JavaScript
"use strict";
|
|
/**
|
|
* @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.AseChannelValidation = void 0;
|
|
const authenticationConstants_1 = require("./authenticationConstants");
|
|
const authenticationConfiguration_1 = require("./authenticationConfiguration");
|
|
const governmentConstants_1 = require("./governmentConstants");
|
|
const credentialProvider_1 = require("./credentialProvider");
|
|
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 AseChannel validation.
|
|
* Validates and Examines JWT tokens from the Bot Framework AseChannel
|
|
*/
|
|
var AseChannelValidation;
|
|
(function (AseChannelValidation) {
|
|
const ChannelId = 'AseChannel';
|
|
let _creadentialProvider;
|
|
let _channelService;
|
|
/**
|
|
* init authentication from user .env configuration.
|
|
*
|
|
* @param configuration The user .env configuration.
|
|
*/
|
|
function init(configuration) {
|
|
const appId = configuration.MicrosoftAppId;
|
|
const tenantId = configuration.MicrosoftAppTenantId;
|
|
_channelService = configuration.ChannelService;
|
|
AseChannelValidation.MetadataUrl =
|
|
_channelService !== undefined && jwtTokenValidation_1.JwtTokenValidation.isGovernment(_channelService)
|
|
? governmentConstants_1.GovernmentConstants.ToBotFromEmulatorOpenIdMetadataUrl
|
|
: authenticationConstants_1.AuthenticationConstants.ToBotFromEmulatorOpenIdMetadataUrl;
|
|
_creadentialProvider = new credentialProvider_1.SimpleCredentialProvider(appId, '');
|
|
const tenantIds = [
|
|
tenantId,
|
|
'f8cdef31-a31e-4b4a-93e4-5f571e91255a',
|
|
'd6d49420-f39b-4df7-a1dc-d59a935871db', // Public botframework.com
|
|
];
|
|
const validIssuers = [];
|
|
tenantIds.forEach((tmpId) => {
|
|
validIssuers.push(`https://sts.windows.net/${tmpId}/`); // Auth Public/US Gov, 1.0 token
|
|
validIssuers.push(`https://login.microsoftonline.com/${tmpId}/v2.0`); // Auth Public, 2.0 token
|
|
validIssuers.push(`https://login.microsoftonline.us/${tmpId}/v2.0`); // Auth for US Gov, 2.0 token
|
|
});
|
|
tokenValidationParameters_1.BetweenBotAndAseChannelTokenValidationParameters.issuer = validIssuers;
|
|
}
|
|
AseChannelValidation.init = init;
|
|
/**
|
|
* Determines if a given Auth header is from the Bot Framework AseChannel
|
|
*
|
|
* @param {string} channelId The channelId.
|
|
* @returns {boolean} True, if the token was issued by the AseChannel. Otherwise, false.
|
|
*/
|
|
function isTokenFromAseChannel(channelId) {
|
|
return channelId === ChannelId;
|
|
}
|
|
AseChannelValidation.isTokenFromAseChannel = isTokenFromAseChannel;
|
|
/**
|
|
* Validate the incoming Auth Header as a token sent from the Bot Framework AseChannel.
|
|
* A token issued by the Bot Framework will FAIL this check. Only AseChannel tokens will pass.
|
|
*
|
|
* @param {string} authHeader The raw HTTP header in the format: 'Bearer [longString]'
|
|
* @param {AuthenticationConfiguration} authConfig The authentication configuration.
|
|
* @returns {Promise<ClaimsIdentity>} A valid ClaimsIdentity.
|
|
*/
|
|
function authenticateAseChannelToken(authHeader, authConfig = new authenticationConfiguration_1.AuthenticationConfiguration()) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const tokenExtractor = new jwtTokenExtractor_1.JwtTokenExtractor(tokenValidationParameters_1.BetweenBotAndAseChannelTokenValidationParameters, AseChannelValidation.MetadataUrl, 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 _creadentialProvider.isValidAppId(appId))) {
|
|
throw new authenticationError_1.AuthenticationError(`Unauthorized. Invalid AppId passed on token: ${appId}`, botframework_schema_1.StatusCodes.UNAUTHORIZED);
|
|
}
|
|
return identity;
|
|
});
|
|
}
|
|
AseChannelValidation.authenticateAseChannelToken = authenticateAseChannelToken;
|
|
})(AseChannelValidation = exports.AseChannelValidation || (exports.AseChannelValidation = {}));
|
|
//# sourceMappingURL=aseChannelValidation.js.map
|