@microsoft/agents-hosting 1.5.0-beta.6.ga236d9a19c → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +10 -9
- package/dist/src/activityHandler.js +2 -2
- package/dist/src/activityHandler.js.map +1 -1
- package/dist/src/agent-client/agentClient.js +49 -40
- package/dist/src/agent-client/agentClient.js.map +1 -1
- package/dist/src/agent-client/agentResponseHandler.js +2 -2
- package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
- package/dist/src/app/agentApplication.d.ts +36 -10
- package/dist/src/app/agentApplication.js +169 -99
- package/dist/src/app/agentApplication.js.map +1 -1
- package/dist/src/app/agentApplicationBuilder.d.ts +15 -0
- package/dist/src/app/agentApplicationBuilder.js +22 -4
- package/dist/src/app/agentApplicationBuilder.js.map +1 -1
- package/dist/src/app/agentApplicationOptions.d.ts +38 -0
- package/dist/src/app/attachmentDownloader.js +2 -2
- package/dist/src/app/attachmentDownloader.js.map +1 -1
- package/dist/src/app/auth/authorization.js +12 -9
- package/dist/src/app/auth/authorization.js.map +1 -1
- package/dist/src/app/auth/authorizationManager.d.ts +18 -5
- package/dist/src/app/auth/authorizationManager.js +258 -45
- package/dist/src/app/auth/authorizationManager.js.map +1 -1
- package/dist/src/app/auth/handlerStorage.js +3 -1
- package/dist/src/app/auth/handlerStorage.js.map +1 -1
- package/dist/src/app/auth/handlers/agenticAuthorization.d.ts +19 -16
- package/dist/src/app/auth/handlers/agenticAuthorization.js +46 -52
- package/dist/src/app/auth/handlers/agenticAuthorization.js.map +1 -1
- package/dist/src/app/auth/handlers/azureBotAuthorization.d.ts +51 -75
- package/dist/src/app/auth/handlers/azureBotAuthorization.js +217 -192
- package/dist/src/app/auth/handlers/azureBotAuthorization.js.map +1 -1
- package/dist/src/app/auth/types.d.ts +100 -1
- package/dist/src/app/auth/utils.d.ts +10 -0
- package/dist/src/app/auth/utils.js +21 -0
- package/dist/src/app/auth/utils.js.map +1 -0
- package/dist/src/app/index.d.ts +1 -0
- package/dist/src/app/index.js +1 -0
- package/dist/src/app/index.js.map +1 -1
- package/dist/src/app/proactive/conversation.d.ts +43 -0
- package/dist/src/app/proactive/conversation.js +67 -0
- package/dist/src/app/proactive/conversation.js.map +1 -0
- package/dist/src/app/proactive/conversationBuilder.d.ts +54 -0
- package/dist/src/app/proactive/conversationBuilder.js +110 -0
- package/dist/src/app/proactive/conversationBuilder.js.map +1 -0
- package/dist/src/app/proactive/conversationReferenceBuilder.d.ts +68 -0
- package/dist/src/app/proactive/conversationReferenceBuilder.js +125 -0
- package/dist/src/app/proactive/conversationReferenceBuilder.js.map +1 -0
- package/dist/src/app/proactive/createConversationOptions.d.ts +30 -0
- package/dist/src/app/proactive/createConversationOptions.js +10 -0
- package/dist/src/app/proactive/createConversationOptions.js.map +1 -0
- package/dist/src/app/proactive/createConversationOptionsBuilder.d.ts +69 -0
- package/dist/src/app/proactive/createConversationOptionsBuilder.js +141 -0
- package/dist/src/app/proactive/createConversationOptionsBuilder.js.map +1 -0
- package/dist/src/app/proactive/index.d.ts +7 -0
- package/dist/src/app/proactive/index.js +26 -0
- package/dist/src/app/proactive/index.js.map +1 -0
- package/dist/src/app/proactive/proactive.d.ts +248 -0
- package/dist/src/app/proactive/proactive.js +310 -0
- package/dist/src/app/proactive/proactive.js.map +1 -0
- package/dist/src/app/proactive/proactiveOptions.d.ts +19 -0
- package/dist/src/app/proactive/proactiveOptions.js +5 -0
- package/dist/src/app/proactive/proactiveOptions.js.map +1 -0
- package/dist/src/app/streaming/streamingResponse.js +2 -2
- package/dist/src/app/streaming/streamingResponse.js.map +1 -1
- package/dist/src/app/teamsAttachmentDownloader.js +2 -2
- package/dist/src/app/teamsAttachmentDownloader.js.map +1 -1
- package/dist/src/app/turnState.js +2 -2
- package/dist/src/app/turnState.js.map +1 -1
- package/dist/src/auth/authConfiguration.d.ts +61 -0
- package/dist/src/auth/authConfiguration.js +52 -3
- package/dist/src/auth/authConfiguration.js.map +1 -1
- package/dist/src/auth/jwt-middleware.js +2 -2
- package/dist/src/auth/jwt-middleware.js.map +1 -1
- package/dist/src/auth/msalConnectionManager.js +20 -0
- package/dist/src/auth/msalConnectionManager.js.map +1 -1
- package/dist/src/auth/msalTokenCredential.js +3 -0
- package/dist/src/auth/msalTokenCredential.js.map +1 -1
- package/dist/src/auth/msalTokenProvider.js +136 -110
- package/dist/src/auth/msalTokenProvider.js.map +1 -1
- package/dist/src/baseAdapter.js +2 -2
- package/dist/src/baseAdapter.js.map +1 -1
- package/dist/src/cloudAdapter.js +201 -154
- package/dist/src/cloudAdapter.js.map +1 -1
- package/dist/src/connector-client/connectorClient.js +176 -127
- package/dist/src/connector-client/connectorClient.js.map +1 -1
- package/dist/src/errorHelper.js +108 -0
- package/dist/src/errorHelper.js.map +1 -1
- package/dist/src/middlewareSet.js +2 -2
- package/dist/src/middlewareSet.js.map +1 -1
- package/dist/src/oauth/userTokenClient.js +78 -48
- package/dist/src/oauth/userTokenClient.js.map +1 -1
- package/dist/src/observability/index.d.ts +2 -0
- package/dist/src/observability/index.js +21 -0
- package/dist/src/observability/index.js.map +1 -0
- package/dist/src/observability/metrics.d.ts +21 -0
- package/dist/src/observability/metrics.js +87 -0
- package/dist/src/observability/metrics.js.map +1 -0
- package/dist/src/observability/traces.d.ts +234 -0
- package/dist/src/observability/traces.js +962 -0
- package/dist/src/observability/traces.js.map +1 -0
- package/dist/src/state/agentState.js +2 -2
- package/dist/src/state/agentState.js.map +1 -1
- package/dist/src/storage/fileStorage.js +38 -28
- package/dist/src/storage/fileStorage.js.map +1 -1
- package/dist/src/storage/memoryStorage.js +41 -30
- package/dist/src/storage/memoryStorage.js.map +1 -1
- package/dist/src/transcript/fileTranscriptLogger.js +2 -2
- package/dist/src/transcript/fileTranscriptLogger.js.map +1 -1
- package/dist/src/transcript/transcriptLoggerMiddleware.js +2 -2
- package/dist/src/transcript/transcriptLoggerMiddleware.js.map +1 -1
- package/dist/src/turnContext.js +48 -42
- package/dist/src/turnContext.js.map +1 -1
- package/package.json +10 -9
- package/src/activityHandler.ts +1 -1
- package/src/agent-client/agentClient.ts +53 -42
- package/src/agent-client/agentResponseHandler.ts +1 -1
- package/src/app/agentApplication.ts +212 -86
- package/src/app/agentApplicationBuilder.ts +26 -4
- package/src/app/agentApplicationOptions.ts +43 -0
- package/src/app/attachmentDownloader.ts +1 -1
- package/src/app/auth/authorization.ts +11 -8
- package/src/app/auth/authorizationManager.ts +297 -45
- package/src/app/auth/handlerStorage.ts +3 -1
- package/src/app/auth/handlers/agenticAuthorization.ts +68 -72
- package/src/app/auth/handlers/azureBotAuthorization.ts +260 -264
- package/src/app/auth/types.ts +102 -1
- package/src/app/auth/utils.ts +22 -0
- package/src/app/index.ts +1 -0
- package/src/app/proactive/conversation.ts +87 -0
- package/src/app/proactive/conversationBuilder.ts +139 -0
- package/src/app/proactive/conversationReferenceBuilder.ts +161 -0
- package/src/app/proactive/createConversationOptions.ts +35 -0
- package/src/app/proactive/createConversationOptionsBuilder.ts +181 -0
- package/src/app/proactive/index.ts +10 -0
- package/src/app/proactive/proactive.ts +524 -0
- package/src/app/proactive/proactiveOptions.ts +24 -0
- package/src/app/streaming/streamingResponse.ts +1 -1
- package/src/app/teamsAttachmentDownloader.ts +1 -1
- package/src/app/turnState.ts +1 -1
- package/src/auth/authConfiguration.ts +58 -1
- package/src/auth/jwt-middleware.ts +1 -1
- package/src/auth/msalConnectionManager.ts +22 -0
- package/src/auth/msalTokenCredential.ts +4 -0
- package/src/auth/msalTokenProvider.ts +138 -107
- package/src/baseAdapter.ts +1 -1
- package/src/cloudAdapter.ts +239 -184
- package/src/connector-client/connectorClient.ts +169 -126
- package/src/errorHelper.ts +124 -0
- package/src/middlewareSet.ts +1 -1
- package/src/oauth/userTokenClient.ts +70 -46
- package/src/observability/index.ts +5 -0
- package/src/observability/metrics.ts +103 -0
- package/src/observability/traces.ts +988 -0
- package/src/state/agentState.ts +1 -1
- package/src/storage/fileStorage.ts +36 -26
- package/src/storage/memoryStorage.ts +40 -29
- package/src/transcript/fileTranscriptLogger.ts +1 -1
- package/src/transcript/transcriptLoggerMiddleware.ts +1 -1
- package/src/turnContext.ts +47 -41
|
@@ -8,14 +8,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
8
8
|
};
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.AzureBotAuthorization = void 0;
|
|
11
|
-
const logger_1 = require("@microsoft/agents-activity/logger");
|
|
12
11
|
const types_1 = require("../types");
|
|
13
12
|
const messageFactory_1 = require("../../../messageFactory");
|
|
14
13
|
const cards_1 = require("../../../cards");
|
|
15
14
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
16
15
|
const handlerStorage_1 = require("../handlerStorage");
|
|
16
|
+
const utils_1 = require("../utils");
|
|
17
17
|
const agents_activity_1 = require("@microsoft/agents-activity");
|
|
18
|
-
const
|
|
18
|
+
const agents_telemetry_1 = require("@microsoft/agents-telemetry");
|
|
19
|
+
const observability_1 = require("../../../observability");
|
|
20
|
+
const errorHelper_1 = require("../../../errorHelper");
|
|
21
|
+
const logger = (0, agents_telemetry_1.debug)('agents:authorization:azurebot');
|
|
19
22
|
const DEFAULT_SIGN_IN_ATTEMPTS = 2;
|
|
20
23
|
var Category;
|
|
21
24
|
(function (Category) {
|
|
@@ -29,72 +32,56 @@ class AzureBotAuthorization {
|
|
|
29
32
|
/**
|
|
30
33
|
* Creates an instance of the AzureBotAuthorization.
|
|
31
34
|
* @param id The unique identifier for the handler.
|
|
32
|
-
* @param options The settings for the handler.
|
|
33
|
-
* @param
|
|
35
|
+
* @param options The settings for the handler (must be fully resolved).
|
|
36
|
+
* @param settings The authorization handler settings.
|
|
34
37
|
*/
|
|
35
38
|
constructor(id, options, settings) {
|
|
36
39
|
this.id = id;
|
|
40
|
+
this.options = options;
|
|
37
41
|
this.settings = settings;
|
|
42
|
+
this.type = 'azurebot';
|
|
38
43
|
this._key = `${AzureBotAuthorization.name}/${this.id}`;
|
|
39
44
|
/**
|
|
40
45
|
* Predefined messages with dynamic placeholders.
|
|
41
46
|
*/
|
|
42
47
|
this.messages = {
|
|
43
48
|
invalidCode: (code) => {
|
|
44
|
-
var _a
|
|
45
|
-
const message = (
|
|
49
|
+
var _a;
|
|
50
|
+
const message = (_a = this.options.invalidSignInRetryMessage) !== null && _a !== void 0 ? _a : 'Invalid **{code}** code entered. Please try again with a new sign-in request.';
|
|
46
51
|
return message.replaceAll('{code}', code);
|
|
47
52
|
},
|
|
48
53
|
invalidCodeFormat: (attemptsLeft) => {
|
|
49
|
-
var _a
|
|
50
|
-
const message = (
|
|
54
|
+
var _a;
|
|
55
|
+
const message = (_a = this.options.invalidSignInRetryMessageFormat) !== null && _a !== void 0 ? _a : 'Please enter a valid **6-digit** code format (_e.g. 123456_).\r\n**{attemptsLeft} attempt(s) left...**';
|
|
51
56
|
return message.replaceAll('{attemptsLeft}', attemptsLeft.toString());
|
|
52
57
|
},
|
|
53
58
|
maxAttemptsExceeded: (maxAttempts) => {
|
|
54
|
-
var _a
|
|
55
|
-
const message = (
|
|
59
|
+
var _a;
|
|
60
|
+
const message = (_a = this.options.invalidSignInRetryMaxExceededMessage) !== null && _a !== void 0 ? _a : 'You have exceeded the maximum number of sign-in attempts ({maxAttempts}). Please try again with a new sign-in request.';
|
|
56
61
|
return message.replaceAll('{maxAttempts}', maxAttempts.toString());
|
|
57
62
|
},
|
|
58
63
|
};
|
|
59
64
|
if (!this.settings.storage) {
|
|
60
|
-
throw
|
|
65
|
+
throw agents_activity_1.ExceptionHelper.generateException(Error, errorHelper_1.Errors.StorageOptionNotAvailable);
|
|
61
66
|
}
|
|
62
67
|
if (!this.settings.connections) {
|
|
63
|
-
throw
|
|
68
|
+
throw agents_activity_1.ExceptionHelper.generateException(Error, errorHelper_1.Errors.ConnectionsOptionNotAvailable);
|
|
69
|
+
}
|
|
70
|
+
if (!options.azureBotOAuthConnectionName) {
|
|
71
|
+
throw agents_activity_1.ExceptionHelper.generateException(Error, errorHelper_1.Errors.AzureBotOAuthConnectionNameRequired);
|
|
64
72
|
}
|
|
65
|
-
this._options = this.loadOptions(options);
|
|
66
73
|
}
|
|
67
74
|
/**
|
|
68
|
-
*
|
|
75
|
+
* The OBO scopes configured for this handler.
|
|
69
76
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const result = {
|
|
73
|
-
name: (_a = settings.name) !== null && _a !== void 0 ? _a : (process.env[`${this.id}_connectionName`]),
|
|
74
|
-
title: (_c = (_b = settings.title) !== null && _b !== void 0 ? _b : (process.env[`${this.id}_connectionTitle`])) !== null && _c !== void 0 ? _c : 'Sign-in',
|
|
75
|
-
text: (_e = (_d = settings.text) !== null && _d !== void 0 ? _d : (process.env[`${this.id}_connectionText`])) !== null && _e !== void 0 ? _e : 'Please sign-in to continue',
|
|
76
|
-
maxAttempts: (_f = settings.maxAttempts) !== null && _f !== void 0 ? _f : parseInt(process.env[`${this.id}_maxAttempts`]),
|
|
77
|
-
messages: {
|
|
78
|
-
invalidCode: (_h = (_g = settings.messages) === null || _g === void 0 ? void 0 : _g.invalidCode) !== null && _h !== void 0 ? _h : process.env[`${this.id}_messages_invalidCode`],
|
|
79
|
-
invalidCodeFormat: (_k = (_j = settings.messages) === null || _j === void 0 ? void 0 : _j.invalidCodeFormat) !== null && _k !== void 0 ? _k : process.env[`${this.id}_messages_invalidCodeFormat`],
|
|
80
|
-
maxAttemptsExceeded: (_m = (_l = settings.messages) === null || _l === void 0 ? void 0 : _l.maxAttemptsExceeded) !== null && _m !== void 0 ? _m : process.env[`${this.id}_messages_maxAttemptsExceeded`],
|
|
81
|
-
},
|
|
82
|
-
obo: {
|
|
83
|
-
connection: (_p = (_o = settings.obo) === null || _o === void 0 ? void 0 : _o.connection) !== null && _p !== void 0 ? _p : process.env[`${this.id}_obo_connection`],
|
|
84
|
-
scopes: (_r = (_q = settings.obo) === null || _q === void 0 ? void 0 : _q.scopes) !== null && _r !== void 0 ? _r : this.loadScopes(process.env[`${this.id}_obo_scopes`]),
|
|
85
|
-
},
|
|
86
|
-
enableSso: process.env[`${this.id}_enableSso`] !== 'false' // default value is true
|
|
87
|
-
};
|
|
88
|
-
if (!result.name) {
|
|
89
|
-
throw new Error(this.prefix(`The 'name' property or '${this.id}_connectionName' env variable is required to initialize the handler.`));
|
|
90
|
-
}
|
|
91
|
-
return result;
|
|
77
|
+
get scopes() {
|
|
78
|
+
return this.options.oboScopes;
|
|
92
79
|
}
|
|
93
80
|
/**
|
|
94
81
|
* Maximum number of attempts for magic code entry.
|
|
95
82
|
*/
|
|
96
83
|
get maxAttempts() {
|
|
97
|
-
const attempts = this.
|
|
84
|
+
const attempts = this.options.invalidSignInRetryMax;
|
|
98
85
|
const result = typeof attempts === 'number' && Number.isFinite(attempts) ? Math.round(attempts) : NaN;
|
|
99
86
|
return result > 0 ? result : DEFAULT_SIGN_IN_ATTEMPTS;
|
|
100
87
|
}
|
|
@@ -120,18 +107,19 @@ class AzureBotAuthorization {
|
|
|
120
107
|
*/
|
|
121
108
|
async token(context, options) {
|
|
122
109
|
var _a;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
token = tokenResponse === null || tokenResponse === void 0 ? void 0 : tokenResponse.token;
|
|
130
|
-
}
|
|
131
|
-
if (!(token === null || token === void 0 ? void 0 : token.trim())) {
|
|
132
|
-
return { token: undefined };
|
|
110
|
+
const oboScopes = (options === null || options === void 0 ? void 0 : options.scopes) && options.scopes.length > 0 ? options.scopes : this.options.oboScopes;
|
|
111
|
+
// OBO token acquisition
|
|
112
|
+
if (oboScopes && oboScopes.length > 0) {
|
|
113
|
+
const oboConnection = (_a = options === null || options === void 0 ? void 0 : options.connection) !== null && _a !== void 0 ? _a : this.options.oboConnectionName;
|
|
114
|
+
const token = await this.getOBOToken(context, oboConnection, oboScopes);
|
|
115
|
+
return { token };
|
|
133
116
|
}
|
|
134
|
-
|
|
117
|
+
// Regular token acquisition
|
|
118
|
+
return (0, agents_telemetry_1.trace)(observability_1.AuthorizationTraceDefinitions.azureBotToken, async ({ record }) => {
|
|
119
|
+
record({ handlerId: this.id, connectionName: this.options.azureBotOAuthConnectionName });
|
|
120
|
+
const token = await this.getBaseToken(context);
|
|
121
|
+
return { token };
|
|
122
|
+
});
|
|
135
123
|
}
|
|
136
124
|
/**
|
|
137
125
|
* Signs out the user from the service.
|
|
@@ -139,17 +127,20 @@ class AzureBotAuthorization {
|
|
|
139
127
|
* @returns True if the signout was successful, false otherwise.
|
|
140
128
|
*/
|
|
141
129
|
async signout(context) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
130
|
+
return (0, agents_telemetry_1.trace)(observability_1.AuthorizationTraceDefinitions.azureBotSignout, async ({ record }) => {
|
|
131
|
+
var _a;
|
|
132
|
+
const user = (_a = context.activity.from) === null || _a === void 0 ? void 0 : _a.id;
|
|
133
|
+
const channel = context.activity.channelId;
|
|
134
|
+
const connection = this.options.azureBotOAuthConnectionName;
|
|
135
|
+
record({ handlerId: this.id, connectionName: connection, channelId: channel !== null && channel !== void 0 ? channel : 'unknown' });
|
|
136
|
+
if (!channel || !user) {
|
|
137
|
+
throw agents_activity_1.ExceptionHelper.generateException(Error, errorHelper_1.Errors.ChannelIdAndFromIdRequiredForSignout);
|
|
138
|
+
}
|
|
139
|
+
logger.debug(this.prefix(`Signing out User '${user}' from => Channel: '${channel}', Connection: '${connection}'`), context.activity);
|
|
140
|
+
const userTokenClient = await this.getUserTokenClient(context);
|
|
141
|
+
await userTokenClient.signOut(user, connection, channel);
|
|
142
|
+
return true;
|
|
143
|
+
});
|
|
153
144
|
}
|
|
154
145
|
/**
|
|
155
146
|
* Initiates the sign-in process for the handler.
|
|
@@ -158,118 +149,172 @@ class AzureBotAuthorization {
|
|
|
158
149
|
* @returns The status of the sign-in attempt.
|
|
159
150
|
*/
|
|
160
151
|
async signin(context, active) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
152
|
+
return (0, agents_telemetry_1.trace)(observability_1.AuthorizationTraceDefinitions.azureBotSignin, async ({ record, actions }) => {
|
|
153
|
+
var _a, _b, _c, _d;
|
|
154
|
+
const reason = { message: '' };
|
|
155
|
+
let status;
|
|
156
|
+
const { activity } = context;
|
|
157
|
+
const [category] = (_b = (_a = activity.name) === null || _a === void 0 ? void 0 : _a.split('/')) !== null && _b !== void 0 ? _b : [Category.UNKNOWN];
|
|
158
|
+
const storage = new handlerStorage_1.HandlerStorage(this.settings.storage, context);
|
|
159
|
+
try {
|
|
160
|
+
if (!active) {
|
|
161
|
+
status = await this.setToken(storage, context, undefined, undefined, reason);
|
|
162
|
+
return status;
|
|
163
|
+
}
|
|
164
|
+
logger.debug(this.prefix('Sign-in active session detected'), active.activity);
|
|
165
|
+
if (active.attemptsLeft <= 0) {
|
|
166
|
+
reason.message = 'Maximum sign-in attempts exceeded';
|
|
167
|
+
logger.warn(this.prefix(reason.message), activity);
|
|
168
|
+
await context.sendActivity(messageFactory_1.MessageFactory.text(this.messages.maxAttemptsExceeded(this.maxAttempts)));
|
|
169
|
+
status = types_1.AuthorizationHandlerStatus.REJECTED;
|
|
170
|
+
return status;
|
|
171
|
+
}
|
|
172
|
+
if (category === Category.SIGNIN) {
|
|
173
|
+
await storage.write({ ...active, category });
|
|
174
|
+
status = await this.handleSignInActivities(context, reason);
|
|
175
|
+
if (status !== types_1.AuthorizationHandlerStatus.IGNORED) {
|
|
176
|
+
return status;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else if (active.category === Category.SIGNIN && activity.channelId === agents_activity_1.Channels.Msteams) {
|
|
180
|
+
// Specific to MS Teams, M365 does not send signin/verifyState when user consent is required.
|
|
181
|
+
// This is only for safety in case of unexpected behaviors during the MS Teams sign-in process,
|
|
182
|
+
// e.g., user interrupts the flow by clicking the Consent Cancel button.
|
|
183
|
+
reason.message = 'The incoming activity will be revalidated due to a change in the sign-in flow';
|
|
184
|
+
logger.warn(this.prefix(reason.message), activity);
|
|
185
|
+
status = types_1.AuthorizationHandlerStatus.REVALIDATE;
|
|
186
|
+
return status;
|
|
187
|
+
}
|
|
188
|
+
const verification = await this.codeVerification(storage, context, active, reason);
|
|
189
|
+
status = verification.status;
|
|
190
|
+
if (status !== types_1.AuthorizationHandlerStatus.APPROVED) {
|
|
191
|
+
return status;
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
const result = await this.setToken(storage, context, active, verification.code, reason);
|
|
195
|
+
status = result;
|
|
196
|
+
if (result !== types_1.AuthorizationHandlerStatus.APPROVED) {
|
|
197
|
+
await (0, utils_1.sendInvokeResponse)(context, { status: 404 });
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
await (0, utils_1.sendInvokeResponse)(context, { status: 200 });
|
|
201
|
+
await ((_c = this._onSuccess) === null || _c === void 0 ? void 0 : _c.call(this, context));
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
await (0, utils_1.sendInvokeResponse)(context, { status: 500 });
|
|
206
|
+
if (error instanceof Error) {
|
|
207
|
+
error.message = this.prefix(error.message);
|
|
208
|
+
}
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
197
211
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
212
|
+
finally {
|
|
213
|
+
await actions.link(storage);
|
|
214
|
+
record({
|
|
215
|
+
handlerId: this.id,
|
|
216
|
+
status: status !== null && status !== void 0 ? status : 'unknown',
|
|
217
|
+
statusReason: reason.message,
|
|
218
|
+
connectionName: (_d = this.options.azureBotOAuthConnectionName) !== null && _d !== void 0 ? _d : 'unknown'
|
|
219
|
+
});
|
|
206
220
|
}
|
|
207
|
-
|
|
208
|
-
}
|
|
221
|
+
});
|
|
209
222
|
}
|
|
210
223
|
/**
|
|
211
|
-
*
|
|
224
|
+
* Retrieves the base token from the turn state or the user token client.
|
|
225
|
+
* @param context The turn context.
|
|
226
|
+
* @returns The token string or undefined if not available.
|
|
212
227
|
*/
|
|
213
|
-
async
|
|
214
|
-
var _a
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
try {
|
|
224
|
-
const provider = oboConnection ? this.settings.connections.getConnection(oboConnection) : this.settings.connections.getDefaultConnection();
|
|
225
|
-
const newToken = await provider.acquireTokenOnBehalfOf(oboScopes, token);
|
|
226
|
-
logger.debug(this.prefix('Successfully acquired on-behalf-of token'), { connection: oboConnection, scopes: oboScopes });
|
|
227
|
-
return { token: newToken };
|
|
228
|
-
}
|
|
229
|
-
catch (error) {
|
|
230
|
-
logger.error(this.prefix('Failed to exchange on-behalf-of token'), { connection: oboConnection, scopes: oboScopes }, error);
|
|
231
|
-
return { token: undefined };
|
|
228
|
+
async getBaseToken(context) {
|
|
229
|
+
var _a;
|
|
230
|
+
const { token } = this.getContext(context);
|
|
231
|
+
if (!(token === null || token === void 0 ? void 0 : token.trim())) {
|
|
232
|
+
const { activity } = context;
|
|
233
|
+
const userTokenClient = await this.getUserTokenClient(context);
|
|
234
|
+
// Using getTokenOrSignInResource instead of getUserToken to avoid HTTP 404 errors.
|
|
235
|
+
const { tokenResponse } = await userTokenClient.getTokenOrSignInResource((_a = activity.from) === null || _a === void 0 ? void 0 : _a.id, this.options.azureBotOAuthConnectionName, activity.channelId, activity.getConversationReference(), activity.relatesTo, '');
|
|
236
|
+
return tokenResponse === null || tokenResponse === void 0 ? void 0 : tokenResponse.token;
|
|
232
237
|
}
|
|
238
|
+
return token;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Acquires an on-behalf-of token for the user based on the provided scopes and connection.
|
|
242
|
+
*/
|
|
243
|
+
async getOBOToken(context, oboConnection, oboScopes) {
|
|
244
|
+
return (0, agents_telemetry_1.trace)(observability_1.AuthorizationTraceDefinitions.azureBotOBOToken, async ({ record }) => {
|
|
245
|
+
var _a, _b;
|
|
246
|
+
record({ handlerId: this.id, connectionName: oboConnection, authScopes: oboScopes });
|
|
247
|
+
const token = await this.getBaseToken(context);
|
|
248
|
+
if (!token) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (!this.isExchangeable(token)) {
|
|
252
|
+
throw agents_activity_1.ExceptionHelper.generateException(Error, errorHelper_1.Errors.AzureBotConnectionTokenNotExchangeable, undefined, { connectionName: this.options.azureBotOAuthConnectionName });
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
const provider = oboConnection ? this.settings.connections.getConnection(oboConnection) : this.settings.connections.getDefaultConnection();
|
|
256
|
+
// Record the connection name again in case it changes.
|
|
257
|
+
record({ connectionName: (_b = (_a = provider === null || provider === void 0 ? void 0 : provider.connectionSettings) === null || _a === void 0 ? void 0 : _a.connectionName) !== null && _b !== void 0 ? _b : oboConnection });
|
|
258
|
+
const newToken = await provider.acquireTokenOnBehalfOf(oboScopes, token);
|
|
259
|
+
logger.debug(this.prefix('Successfully acquired on-behalf-of token'), { connection: oboConnection, scopes: oboScopes });
|
|
260
|
+
return newToken;
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
logger.error(this.prefix('Failed to exchange on-behalf-of token'), { connection: oboConnection, scopes: oboScopes }, error);
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
});
|
|
233
267
|
}
|
|
234
268
|
/**
|
|
235
269
|
* Checks if a token is exchangeable for an on-behalf-of flow.
|
|
236
270
|
*/
|
|
237
271
|
isExchangeable(token) {
|
|
272
|
+
var _a;
|
|
238
273
|
if (!token || typeof token !== 'string') {
|
|
239
274
|
return false;
|
|
240
275
|
}
|
|
241
276
|
const payload = jsonwebtoken_1.default.decode(token);
|
|
277
|
+
if (!payload || typeof payload === 'string') {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
const appid = (_a = payload.azp) !== null && _a !== void 0 ? _a : payload.appid;
|
|
281
|
+
if (typeof appid !== 'string' || appid.length === 0) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
242
284
|
const audiences = Array.isArray(payload.aud) ? payload.aud : [payload.aud];
|
|
243
|
-
return audiences.some(aud => typeof aud === 'string' && aud.
|
|
285
|
+
return audiences.some(aud => typeof aud === 'string' && aud.includes(appid));
|
|
244
286
|
}
|
|
245
287
|
/**
|
|
246
288
|
* Sets the token from the token response or initiates the sign-in flow.
|
|
247
289
|
*/
|
|
248
|
-
async setToken(storage, context, active, code) {
|
|
290
|
+
async setToken(storage, context, active, code, reason = { message: '' }) {
|
|
249
291
|
var _a;
|
|
250
292
|
const { activity } = context;
|
|
251
293
|
const userTokenClient = await this.getUserTokenClient(context);
|
|
252
|
-
const { tokenResponse, signInResource } = await userTokenClient.getTokenOrSignInResource((_a = activity.from) === null || _a === void 0 ? void 0 : _a.id, this.
|
|
253
|
-
if (!tokenResponse && active) {
|
|
254
|
-
|
|
255
|
-
|
|
294
|
+
const { tokenResponse, signInResource } = await userTokenClient.getTokenOrSignInResource((_a = activity.from) === null || _a === void 0 ? void 0 : _a.id, this.options.azureBotOAuthConnectionName, activity.channelId, activity.getConversationReference(), activity.relatesTo, code !== null && code !== void 0 ? code : '');
|
|
295
|
+
if (!tokenResponse && active && code) {
|
|
296
|
+
reason.message = 'Invalid code entered. Restarting sign-in flow';
|
|
297
|
+
logger.warn(this.prefix(reason.message), activity);
|
|
298
|
+
await context.sendActivity(messageFactory_1.MessageFactory.text(this.messages.invalidCode(code)));
|
|
256
299
|
return types_1.AuthorizationHandlerStatus.REJECTED;
|
|
257
300
|
}
|
|
258
301
|
if (!tokenResponse) {
|
|
259
|
-
|
|
260
|
-
|
|
302
|
+
reason.message = 'Cannot find token. Sending sign-in card';
|
|
303
|
+
logger.debug(this.prefix(reason.message), activity);
|
|
304
|
+
const oCard = cards_1.CardFactory.oauthCard(this.options.azureBotOAuthConnectionName, this.options.title, this.options.text, signInResource, this.options.enableSso);
|
|
261
305
|
await context.sendActivity(messageFactory_1.MessageFactory.attachment(oCard));
|
|
262
306
|
await storage.write({ activity, id: this.id, ...(active !== null && active !== void 0 ? active : {}), attemptsLeft: this.maxAttempts });
|
|
263
307
|
return types_1.AuthorizationHandlerStatus.PENDING;
|
|
264
308
|
}
|
|
265
|
-
|
|
309
|
+
reason.message = 'Successfully acquired token';
|
|
310
|
+
logger.debug(this.prefix(reason.message), activity);
|
|
266
311
|
this.setContext(context, { token: tokenResponse.token });
|
|
267
312
|
return types_1.AuthorizationHandlerStatus.APPROVED;
|
|
268
313
|
}
|
|
269
314
|
/**
|
|
270
315
|
* Handles sign-in related activities.
|
|
271
316
|
*/
|
|
272
|
-
async handleSignInActivities(context) {
|
|
317
|
+
async handleSignInActivities(context, reason) {
|
|
273
318
|
var _a, _b, _c, _d;
|
|
274
319
|
const { activity } = context;
|
|
275
320
|
// Ignore signin/verifyState here (handled in codeVerification).
|
|
@@ -281,64 +326,66 @@ class AzureBotAuthorization {
|
|
|
281
326
|
const tokenExchangeInvokeRequest = activity.value;
|
|
282
327
|
const tokenExchangeRequest = { token: tokenExchangeInvokeRequest === null || tokenExchangeInvokeRequest === void 0 ? void 0 : tokenExchangeInvokeRequest.token };
|
|
283
328
|
if (!(tokenExchangeRequest === null || tokenExchangeRequest === void 0 ? void 0 : tokenExchangeRequest.token)) {
|
|
284
|
-
|
|
285
|
-
await
|
|
329
|
+
reason.message = 'The Agent received an InvokeActivity that is missing a TokenExchangeInvokeRequest value. This is required to be sent with the InvokeActivity.';
|
|
330
|
+
await (0, utils_1.sendInvokeResponse)(context, {
|
|
286
331
|
status: 400,
|
|
287
|
-
body: { connectionName: this.
|
|
332
|
+
body: { connectionName: this.options.azureBotOAuthConnectionName, failureDetail: reason.message }
|
|
288
333
|
});
|
|
289
|
-
logger.error(this.prefix(reason));
|
|
290
|
-
await ((_a = this._onFailure) === null || _a === void 0 ? void 0 : _a.call(this, context, reason));
|
|
334
|
+
logger.error(this.prefix(reason.message));
|
|
335
|
+
await ((_a = this._onFailure) === null || _a === void 0 ? void 0 : _a.call(this, context, reason.message));
|
|
291
336
|
return types_1.AuthorizationHandlerStatus.REJECTED;
|
|
292
337
|
}
|
|
293
|
-
if (tokenExchangeInvokeRequest.connectionName !== this.
|
|
294
|
-
|
|
295
|
-
await
|
|
338
|
+
if (tokenExchangeInvokeRequest.connectionName !== this.options.azureBotOAuthConnectionName) {
|
|
339
|
+
reason.message = `The Agent received an InvokeActivity with a TokenExchangeInvokeRequest for a different connection name ('${tokenExchangeInvokeRequest.connectionName}') than expected ('${this.options.azureBotOAuthConnectionName}').`;
|
|
340
|
+
await (0, utils_1.sendInvokeResponse)(context, {
|
|
296
341
|
status: 400,
|
|
297
|
-
body: { id: tokenExchangeInvokeRequest.id, connectionName: this.
|
|
342
|
+
body: { id: tokenExchangeInvokeRequest.id, connectionName: this.options.azureBotOAuthConnectionName, failureDetail: reason.message }
|
|
298
343
|
});
|
|
299
|
-
logger.error(this.prefix(reason));
|
|
300
|
-
await ((_b = this._onFailure) === null || _b === void 0 ? void 0 : _b.call(this, context, reason));
|
|
344
|
+
logger.error(this.prefix(reason.message));
|
|
345
|
+
await ((_b = this._onFailure) === null || _b === void 0 ? void 0 : _b.call(this, context, reason.message));
|
|
301
346
|
return types_1.AuthorizationHandlerStatus.REJECTED;
|
|
302
347
|
}
|
|
303
|
-
const { token } = await userTokenClient.exchangeTokenAsync((_c = activity.from) === null || _c === void 0 ? void 0 : _c.id, this.
|
|
348
|
+
const { token } = await userTokenClient.exchangeTokenAsync((_c = activity.from) === null || _c === void 0 ? void 0 : _c.id, this.options.azureBotOAuthConnectionName, activity.channelId, tokenExchangeRequest);
|
|
304
349
|
if (!token) {
|
|
305
|
-
|
|
306
|
-
await
|
|
350
|
+
reason.message = 'The MS Teams token service didn\'t send back the exchanged token. Waiting for MS Teams to send another signin/tokenExchange request. After multiple failed attempts, the user will be asked to enter the magic code.';
|
|
351
|
+
await (0, utils_1.sendInvokeResponse)(context, {
|
|
307
352
|
status: 412,
|
|
308
|
-
body: { id: tokenExchangeInvokeRequest.id, connectionName: this.
|
|
353
|
+
body: { id: tokenExchangeInvokeRequest.id, connectionName: this.options.azureBotOAuthConnectionName, failureDetail: reason.message }
|
|
309
354
|
});
|
|
310
|
-
logger.debug(this.prefix(reason));
|
|
355
|
+
logger.debug(this.prefix(reason.message));
|
|
311
356
|
return types_1.AuthorizationHandlerStatus.PENDING;
|
|
312
357
|
}
|
|
313
|
-
await
|
|
358
|
+
await (0, utils_1.sendInvokeResponse)(context, {
|
|
314
359
|
status: 200,
|
|
315
|
-
body: { id: tokenExchangeInvokeRequest.id, connectionName: this.
|
|
360
|
+
body: { id: tokenExchangeInvokeRequest.id, connectionName: this.options.azureBotOAuthConnectionName }
|
|
316
361
|
});
|
|
317
|
-
|
|
362
|
+
reason.message = 'Successfully exchanged token';
|
|
363
|
+
logger.debug(this.prefix(reason.message));
|
|
318
364
|
this.setContext(context, { token });
|
|
319
365
|
await ((_d = this._onSuccess) === null || _d === void 0 ? void 0 : _d.call(this, context));
|
|
320
366
|
return types_1.AuthorizationHandlerStatus.APPROVED;
|
|
321
367
|
}
|
|
322
368
|
if (activity.name === 'signin/failure') {
|
|
323
|
-
await
|
|
324
|
-
|
|
369
|
+
await (0, utils_1.sendInvokeResponse)(context, { status: 200 });
|
|
370
|
+
reason.message = 'Failed to sign-in';
|
|
325
371
|
const value = activity.value;
|
|
326
|
-
logger.error(this.prefix(reason), value, activity);
|
|
372
|
+
logger.error(this.prefix(reason.message), value, activity);
|
|
327
373
|
if (this._onFailure) {
|
|
328
|
-
await this._onFailure(context, value.message || reason);
|
|
374
|
+
await this._onFailure(context, value.message || reason.message);
|
|
329
375
|
}
|
|
330
376
|
else {
|
|
331
|
-
await context.sendActivity(messageFactory_1.MessageFactory.text(`${reason}. Please try again.`));
|
|
377
|
+
await context.sendActivity(messageFactory_1.MessageFactory.text(`${reason.message}. Please try again.`));
|
|
332
378
|
}
|
|
333
379
|
return types_1.AuthorizationHandlerStatus.REJECTED;
|
|
334
380
|
}
|
|
335
|
-
|
|
381
|
+
reason.message = `Unknown sign-in activity name: ${activity.name}`;
|
|
382
|
+
logger.error(this.prefix(reason.message), activity);
|
|
336
383
|
return types_1.AuthorizationHandlerStatus.REJECTED;
|
|
337
384
|
}
|
|
338
385
|
/**
|
|
339
386
|
* Verifies the magic code provided by the user.
|
|
340
387
|
*/
|
|
341
|
-
async codeVerification(storage, context, active) {
|
|
388
|
+
async codeVerification(storage, context, active, reason = { message: '' }) {
|
|
342
389
|
if (!active) {
|
|
343
390
|
logger.debug(this.prefix('No active session found. Skipping code verification.'), context.activity);
|
|
344
391
|
return { status: types_1.AuthorizationHandlerStatus.IGNORED };
|
|
@@ -351,18 +398,21 @@ class AzureBotAuthorization {
|
|
|
351
398
|
state = teamsState;
|
|
352
399
|
}
|
|
353
400
|
if (state === 'CancelledByUser') {
|
|
354
|
-
await
|
|
355
|
-
|
|
401
|
+
await (0, utils_1.sendInvokeResponse)(context, { status: 200 });
|
|
402
|
+
reason.message = 'Sign-in process was cancelled by the user';
|
|
403
|
+
logger.warn(this.prefix(reason.message), activity);
|
|
356
404
|
return { status: types_1.AuthorizationHandlerStatus.REJECTED };
|
|
357
405
|
}
|
|
358
406
|
if (!(state === null || state === void 0 ? void 0 : state.match(/^\d{6}$/))) {
|
|
359
|
-
|
|
407
|
+
reason.message = `Invalid magic code entered. Attempts left: ${active.attemptsLeft}`;
|
|
408
|
+
logger.warn(this.prefix(reason.message), activity);
|
|
360
409
|
await context.sendActivity(messageFactory_1.MessageFactory.text(this.messages.invalidCodeFormat(active.attemptsLeft)));
|
|
361
410
|
await storage.write({ ...active, attemptsLeft: active.attemptsLeft - 1 });
|
|
362
411
|
return { status: types_1.AuthorizationHandlerStatus.PENDING };
|
|
363
412
|
}
|
|
364
|
-
await
|
|
365
|
-
|
|
413
|
+
await (0, utils_1.sendInvokeResponse)(context, { status: 200 });
|
|
414
|
+
reason.message = 'Code verification successful';
|
|
415
|
+
logger.debug(this.prefix(reason.message), activity);
|
|
366
416
|
return { status: types_1.AuthorizationHandlerStatus.APPROVED, code: state };
|
|
367
417
|
}
|
|
368
418
|
/**
|
|
@@ -385,41 +435,16 @@ class AzureBotAuthorization {
|
|
|
385
435
|
async getUserTokenClient(context) {
|
|
386
436
|
const userTokenClient = context.turnState.get(context.adapter.UserTokenClientKey);
|
|
387
437
|
if (!userTokenClient) {
|
|
388
|
-
throw
|
|
438
|
+
throw agents_activity_1.ExceptionHelper.generateException(Error, errorHelper_1.Errors.UserTokenClientNotAvailable);
|
|
389
439
|
}
|
|
390
440
|
return userTokenClient;
|
|
391
441
|
}
|
|
392
|
-
/**
|
|
393
|
-
* Sends an InvokeResponse activity if the channel is Microsoft Teams, including Copilot within MS Teams.
|
|
394
|
-
*/
|
|
395
|
-
sendInvokeResponse(context, response) {
|
|
396
|
-
if (context.activity.channelIdChannel !== agents_activity_1.Channels.Msteams) {
|
|
397
|
-
return Promise.resolve();
|
|
398
|
-
}
|
|
399
|
-
return context.sendActivity(agents_activity_1.Activity.fromObject({
|
|
400
|
-
type: agents_activity_1.ActivityTypes.InvokeResponse,
|
|
401
|
-
value: response
|
|
402
|
-
}));
|
|
403
|
-
}
|
|
404
442
|
/**
|
|
405
443
|
* Prefixes a message with the handler ID.
|
|
406
444
|
*/
|
|
407
445
|
prefix(message) {
|
|
408
446
|
return `[handler:${this.id}] ${message}`;
|
|
409
447
|
}
|
|
410
|
-
/**
|
|
411
|
-
* Loads the OAuth scopes from the environment variables.
|
|
412
|
-
*/
|
|
413
|
-
loadScopes(value) {
|
|
414
|
-
var _a;
|
|
415
|
-
return (_a = value === null || value === void 0 ? void 0 : value.split(',').reduce((acc, scope) => {
|
|
416
|
-
const trimmed = scope.trim();
|
|
417
|
-
if (trimmed) {
|
|
418
|
-
acc.push(trimmed);
|
|
419
|
-
}
|
|
420
|
-
return acc;
|
|
421
|
-
}, [])) !== null && _a !== void 0 ? _a : [];
|
|
422
|
-
}
|
|
423
448
|
}
|
|
424
449
|
exports.AzureBotAuthorization = AzureBotAuthorization;
|
|
425
450
|
//# sourceMappingURL=azureBotAuthorization.js.map
|