@microsoft/teams-ai
Version:
SDK focused on building AI based applications for Microsoft Teams.
324 lines • 13.2 kB
JavaScript
"use strict";
/**
* @module teams-ai
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthError = exports.AuthenticationManager = exports.Authentication = void 0;
const msal_node_1 = require("@azure/msal-node");
const BotAuthenticationBase_1 = require("./BotAuthenticationBase");
const OAuthAdaptiveCardAuthentication_1 = require("./OAuthAdaptiveCardAuthentication");
const OAuthBotAuthentication_1 = require("./OAuthBotAuthentication");
const OAuthMessageExtensionAuthentication_1 = require("./OAuthMessageExtensionAuthentication");
const TeamsSsoAdaptiveCardAuthentication_1 = require("./TeamsSsoAdaptiveCardAuthentication");
const TeamsSsoBotAuthentication_1 = require("./TeamsSsoBotAuthentication");
const TeamsSsoMessageExtensionAuthentication_1 = require("./TeamsSsoMessageExtensionAuthentication");
const UserTokenAccess = __importStar(require("./UserTokenAccess"));
/**
* User authentication service.
*/
class Authentication {
_adaptiveCardAuth;
_messageExtensionAuth;
_botAuth;
_name;
_msal;
/**
* The authentication settings.
*/
settings;
/**
* Creates a new instance of the `Authentication` class.
* @param {Application} app - The application instance.
* @param {string} name - The name of the connection.
* @param {OAuthSettings} settings - Authentication settings.
* @param {Storage} storage - A storage instance otherwise Memory Storage is used.
* @param {MessageExtensionAuthenticationBase} messageExtensionsAuth - Handles message extension flow authentication.
* @param {BotAuthenticationBase} botAuth - Handles bot-flow authentication.
* @param {AdaptiveCardAuthenticationBase} adaptiveCardAuth - Handles adaptive card authentication.
*/
constructor(app, name, settings, storage, messageExtensionsAuth, botAuth, adaptiveCardAuth) {
this.settings = settings;
this._name = name;
if (this.isOAuthSettings(settings)) {
this._messageExtensionAuth =
messageExtensionsAuth || new OAuthMessageExtensionAuthentication_1.OAuthPromptMessageExtensionAuthentication(settings);
this._botAuth = botAuth || new OAuthBotAuthentication_1.OAuthBotAuthentication(app, settings, this._name, storage);
this._adaptiveCardAuth = adaptiveCardAuth || new OAuthAdaptiveCardAuthentication_1.OAuthAdaptiveCardAuthentication(settings);
}
else {
this._msal = new msal_node_1.ConfidentialClientApplication(settings.msalConfig);
this._botAuth = botAuth || new TeamsSsoBotAuthentication_1.TeamsSsoBotAuthentication(app, settings, this._name, this._msal, storage);
this._messageExtensionAuth =
messageExtensionsAuth || new TeamsSsoMessageExtensionAuthentication_1.TeamsSsoMessageExtensionAuthentication(settings, this._msal);
this._adaptiveCardAuth = adaptiveCardAuth || new TeamsSsoAdaptiveCardAuthentication_1.TeamsSsoAdaptiveCardAuthentication();
}
}
/**
* Signs in a user.
* This method will be called automatically by the Application class.
* @template TState
* @param {TurnContext} context - Current turn context.
* @param {TState} state Application state.
* @returns {string | undefined} The authentication token or undefined if the user is still login in.
*/
async signInUser(context, state) {
// Check if user is signed in.
const token = await this.isUserSignedIn(context);
if (token) {
return token;
}
if (this._messageExtensionAuth.isValidActivity(context)) {
return await this._messageExtensionAuth.authenticate(context);
}
if (this._botAuth.isValidActivity(context)) {
return await this._botAuth.authenticate(context, state);
}
if (this._adaptiveCardAuth.isValidActivity(context)) {
return await this._adaptiveCardAuth.authenticate(context);
}
throw new AuthError('Incoming activity is not a valid activity to initiate authentication flow.', 'invalidActivity');
}
/**
* Signs out a user.
* @template TState
* @param {TurnContext} context - Current turn context.
* @param {TState} state - Application state.
* @returns {Promise<void>} A Promise representing the asynchronous operation.
*/
async signOutUser(context, state) {
this._botAuth.deleteAuthFlowState(context, state);
// Signout flow is agnostic of the activity type.
if (this.isOAuthSettings(this.settings)) {
return await UserTokenAccess.signOutUser(context, this.settings);
}
else {
return await this.removeTokenFromMsalCache(context);
}
}
/**
* Check if the user is signed, if they are then return the token.
* @param {TurnContext} context Current turn context.
* @returns {string | undefined} The token string or undefined if the user is not signed in.
*/
async isUserSignedIn(context) {
if (this.isOAuthSettings(this.settings)) {
const tokenResponse = await UserTokenAccess.getUserToken(context, this.settings, '');
if (tokenResponse && tokenResponse.token) {
return tokenResponse.token;
}
return undefined;
}
else {
const tokenResponse = await this.acquireTokenFromMsalCache(context);
if (tokenResponse && tokenResponse.accessToken) {
return tokenResponse.accessToken;
}
return undefined;
}
}
/**
* The handler function is called when the user has successfully signed in.
* This only applies if sign in was initiated by the user sending a message to the bot.
* This handler will not be triggered if a message extension triggered the authentication flow.
* @template TState
* @param {(context: TurnContext, state: TState) => Promise<void>} handler The handler function to call when the user has successfully signed in
*/
onUserSignInSuccess(handler) {
this._botAuth.onUserSignInSuccess(handler);
}
/**
* This handler function is called when the user sign in flow fails.
* This only applies if sign in was initiated by the user sending a message to the bot.
* This handler will not be triggered if a message extension triggered the authentication flow.
* @template TState
* @param {(context: TurnContext, state: TState, error: AuthError) => Promise<void>} handler The handler function to call when the user failed to signed in.
*/
onUserSignInFailure(handler) {
this._botAuth.onUserSignInFailure(handler);
}
isOAuthSettings(settings) {
return settings.connectionName !== undefined;
}
async acquireTokenFromMsalCache(context) {
try {
if (context.activity.from.aadObjectId) {
const settings = this.settings;
const account = await this._msal.getTokenCache().getAccountByLocalId(context.activity.from.aadObjectId);
if (account) {
const silentRequest = {
account: account,
scopes: settings.scopes
};
return await this._msal.acquireTokenSilent(silentRequest);
}
}
}
catch (error) {
return null;
}
return null;
}
async removeTokenFromMsalCache(context) {
if (context.activity.from.aadObjectId) {
try {
const account = await this._msal.getTokenCache().getAccountByLocalId(context.activity.from.aadObjectId);
if (account) {
await this._msal.getTokenCache().removeAccount(account);
}
}
catch (error) {
return;
}
}
return;
}
}
exports.Authentication = Authentication;
/**
* The user authentication manager.
*/
class AuthenticationManager {
_authentications = new Map();
default;
/**
* Creates a new instance of the `AuthenticationManager` class.
* @param {Application} app - The application instance.
* @param {AuthenticationOptions} options - Authentication options.
* @param {Storage} storage - A storage instance otherwise Memory Storage is used.
*/
constructor(app, options, storage) {
if (!options.settings || Object.keys(options.settings).length === 0) {
throw new Error('Authentication settings are required.');
}
this.default = options.default || Object.keys(options.settings)[0];
const settings = options.settings;
for (const key in settings) {
if (key in settings) {
const setting = settings[key];
const authentication = new Authentication(app, key, setting, storage);
this._authentications.set(key, authentication);
}
}
}
/**
* @template TState
* Gets the authentication instance for the specified connection name.
* @param {string} name The setting name.
* @returns {Authentication<TState>} The authentication instance.
*/
get(name) {
const connection = this._authentications.get(name);
if (!connection) {
throw new Error(`Could not find setting name '${name}'`);
}
return connection;
}
/**
* Signs in a user.
* @template TState
* @param {TurnContext} context The turn context.
* @param {TState} state The turn state.
* @param {string} settingName Optional. The name of the setting to use. If not specified, the default setting name is used.
* @returns {Promise<SignInResponse>} The sign in response.
*/
async signUserIn(context, state, settingName) {
if (!settingName) {
settingName = this.default;
}
// Get authentication instance
const auth = this.get(settingName);
let status;
// Sign the user in
let token;
try {
// Get the auth token
token = await auth.signInUser(context, state);
}
catch (e) {
status = 'error';
const cause = e instanceof AuthError ? e.cause : 'other';
return {
status: status,
cause: cause,
error: e
};
}
if (token) {
(0, BotAuthenticationBase_1.setTokenInState)(state, settingName, token);
status = 'complete';
}
else {
status = 'pending';
}
return {
status
};
}
/**
* Signs out a user.
* @template TState
* @param {TurnContext} context The turn context.
* @param {TState} state The turn state.
* @param {string} settingName Optional. The name of the setting to use. If not specified, the default setting name is used.
*/
async signOutUser(context, state, settingName) {
if (!settingName) {
settingName = this.default;
}
// Get authentication instace
const auth = this.get(settingName);
// Sign the user out
if (auth) {
await auth.signOutUser(context, state);
(0, BotAuthenticationBase_1.deleteTokenFromState)(state, settingName);
}
}
}
exports.AuthenticationManager = AuthenticationManager;
/**
* An error thrown when an authentication error occurs.
*/
class AuthError extends Error {
/**
* The cause of the error.
*/
cause;
/**
* Creates a new instance of the `AuthError` class.
* @param {string} message The error message.
* @param {AuthErrorReason} reason Optional. Cause of the error. Defaults to `other`.
*/
constructor(message, reason = 'other') {
super(message);
this.cause = reason;
}
}
exports.AuthError = AuthError;
//# sourceMappingURL=Authentication.js.map