@microsoft/agents-hosting 1.6.0-beta.8.g226709c215 → 1.6.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 +4 -9
- package/dist/src/agent-client/agentClient.js +2 -2
- 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.js +28 -2
- package/dist/src/app/agentApplication.js.map +1 -1
- package/dist/src/app/agentApplicationOptions.d.ts +10 -0
- package/dist/src/app/attachmentDownloader.js +5 -10
- package/dist/src/app/attachmentDownloader.js.map +1 -1
- package/dist/src/app/auth/authorizationManager.d.ts +4 -0
- package/dist/src/app/auth/authorizationManager.js +94 -67
- package/dist/src/app/auth/authorizationManager.js.map +1 -1
- package/dist/src/app/auth/handlers/azureBotAuthorization.js +2 -2
- package/dist/src/app/auth/handlers/azureBotAuthorization.js.map +1 -1
- package/dist/src/app/proactive/createConversationOptionsBuilder.js +10 -6
- package/dist/src/app/proactive/createConversationOptionsBuilder.js.map +1 -1
- package/dist/src/app/proactive/proactive.d.ts +1 -0
- package/dist/src/app/proactive/proactive.js +30 -15
- package/dist/src/app/proactive/proactive.js.map +1 -1
- package/dist/src/app/teamsAttachmentDownloader.js +6 -8
- package/dist/src/app/teamsAttachmentDownloader.js.map +1 -1
- package/dist/src/auth/authConfiguration.d.ts +2 -143
- package/dist/src/auth/authConfiguration.js +301 -257
- package/dist/src/auth/authConfiguration.js.map +1 -1
- package/dist/src/auth/jwt-middleware.js +2 -1
- package/dist/src/auth/jwt-middleware.js.map +1 -1
- package/dist/src/auth/msalConnectionManager.js +27 -14
- package/dist/src/auth/msalConnectionManager.js.map +1 -1
- package/dist/src/auth/msalTokenProvider.d.ts +7 -0
- package/dist/src/auth/msalTokenProvider.js +188 -44
- package/dist/src/auth/msalTokenProvider.js.map +1 -1
- package/dist/src/auth/settings.d.ts +327 -0
- package/dist/src/auth/settings.js +158 -0
- package/dist/src/auth/settings.js.map +1 -0
- package/dist/src/cloudAdapter.d.ts +58 -1
- package/dist/src/cloudAdapter.js +232 -52
- package/dist/src/cloudAdapter.js.map +1 -1
- package/dist/src/connector-client/connectorClient.d.ts +12 -8
- package/dist/src/connector-client/connectorClient.js +99 -82
- package/dist/src/connector-client/connectorClient.js.map +1 -1
- package/dist/src/errorHelper.js +85 -7
- package/dist/src/errorHelper.js.map +1 -1
- package/dist/src/getProductInfo.d.ts +23 -0
- package/dist/src/getProductInfo.js +71 -1
- package/dist/src/getProductInfo.js.map +1 -1
- package/dist/src/headerPropagation.d.ts +17 -2
- package/dist/src/headerPropagation.js +46 -24
- package/dist/src/headerPropagation.js.map +1 -1
- package/dist/src/httpClient.d.ts +60 -0
- package/dist/src/httpClient.js +173 -0
- package/dist/src/httpClient.js.map +1 -0
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.js +7 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/oauth/userTokenClient.d.ts +5 -4
- package/dist/src/oauth/userTokenClient.js +97 -78
- package/dist/src/oauth/userTokenClient.js.map +1 -1
- package/dist/src/observability/traces.d.ts +11 -4
- package/dist/src/observability/traces.js +39 -7
- package/dist/src/observability/traces.js.map +1 -1
- package/dist/src/utils/env.d.ts +50 -0
- package/dist/src/utils/env.js +113 -0
- package/dist/src/utils/env.js.map +1 -0
- package/dist/src/utils.d.ts +10 -0
- package/dist/src/utils.js +18 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +4 -9
- package/src/agent-client/agentClient.ts +2 -2
- package/src/agent-client/agentResponseHandler.ts +2 -2
- package/src/app/agentApplication.ts +30 -3
- package/src/app/agentApplicationOptions.ts +11 -0
- package/src/app/attachmentDownloader.ts +6 -8
- package/src/app/auth/authorizationManager.ts +84 -41
- package/src/app/auth/handlers/azureBotAuthorization.ts +2 -2
- package/src/app/proactive/createConversationOptionsBuilder.ts +8 -4
- package/src/app/proactive/proactive.ts +39 -23
- package/src/app/teamsAttachmentDownloader.ts +7 -6
- package/src/auth/authConfiguration.ts +317 -356
- package/src/auth/jwt-middleware.ts +1 -1
- package/src/auth/msalConnectionManager.ts +27 -10
- package/src/auth/msalTokenProvider.ts +180 -42
- package/src/auth/settings.ts +323 -0
- package/src/cloudAdapter.ts +291 -12
- package/src/connector-client/connectorClient.ts +116 -94
- package/src/errorHelper.ts +96 -7
- package/src/getProductInfo.ts +79 -1
- package/src/headerPropagation.ts +55 -23
- package/src/httpClient.ts +223 -0
- package/src/index.ts +5 -1
- package/src/oauth/userTokenClient.ts +103 -84
- package/src/observability/traces.ts +39 -8
- package/src/utils/env.ts +105 -0
- package/src/utils.ts +14 -0
|
@@ -21,7 +21,7 @@ const logger = debug('agents:jwt-middleware')
|
|
|
21
21
|
export function buildJwksUri (iss: string, authConfig: AuthConfiguration): string {
|
|
22
22
|
return iss === 'https://api.botframework.com'
|
|
23
23
|
? 'https://login.botframework.com/v1/.well-known/keys'
|
|
24
|
-
: `${resolveAuthority(authConfig.authority, authConfig.tenantId)}/discovery/v2.0/keys`
|
|
24
|
+
: `${resolveAuthority(authConfig.authorityEndpoint ?? authConfig.authority, authConfig.tenantId)}/discovery/v2.0/keys`
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { Activity, RoleTypes } from '@microsoft/agents-activity'
|
|
7
7
|
import { debug } from '@microsoft/agents-telemetry'
|
|
8
|
-
import { AuthConfiguration, resolveAuthority } from './authConfiguration'
|
|
8
|
+
import { AuthConfiguration, AuthType, resolveAuthority } from './authConfiguration'
|
|
9
9
|
import { Connections } from './connections'
|
|
10
10
|
import { MsalTokenProvider } from './msalTokenProvider'
|
|
11
11
|
import { JwtPayload } from 'jsonwebtoken'
|
|
@@ -44,13 +44,16 @@ export class MsalConnectionManager implements Connections {
|
|
|
44
44
|
|
|
45
45
|
for (const [name, provider] of this._connections.entries()) {
|
|
46
46
|
const cfg = provider.connectionSettings
|
|
47
|
-
const authType = cfg?.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
const authType = cfg?.authType ??
|
|
48
|
+
(cfg?.certPemFile
|
|
49
|
+
? AuthType.Certificate
|
|
50
|
+
: cfg?.clientSecret
|
|
51
|
+
? AuthType.ClientSecret
|
|
52
|
+
: cfg?.WIDAssertionFile
|
|
53
|
+
? AuthType.WorkloadIdentity
|
|
54
|
+
: cfg?.federatedClientId || cfg?.FICClientId
|
|
55
|
+
? AuthType.FederatedCredentials
|
|
56
|
+
: 'none')
|
|
54
57
|
logger.debug('connection "%s" clientId=%s tenantId=%s authType=%s', name, cfg?.clientId ?? '<none>', cfg?.tenantId ?? '<none>', authType)
|
|
55
58
|
}
|
|
56
59
|
|
|
@@ -185,13 +188,27 @@ export class MsalConnectionManager implements Connections {
|
|
|
185
188
|
|
|
186
189
|
private applyConnectionDefaults (conn: MsalTokenProvider): MsalTokenProvider {
|
|
187
190
|
if (conn.connectionSettings) {
|
|
188
|
-
conn.connectionSettings.
|
|
191
|
+
conn.connectionSettings.authorityEndpoint ??= conn.connectionSettings.authority || 'https://login.microsoftonline.com'
|
|
192
|
+
conn.connectionSettings.authority ??= conn.connectionSettings.authorityEndpoint
|
|
189
193
|
conn.connectionSettings.issuers ??= [
|
|
190
194
|
'https://api.botframework.com',
|
|
191
195
|
`${resolveAuthority('https://sts.windows.net', conn.connectionSettings.tenantId)}/`,
|
|
192
|
-
`${resolveAuthority(conn.connectionSettings.
|
|
196
|
+
`${resolveAuthority(conn.connectionSettings.authorityEndpoint, conn.connectionSettings.tenantId)}/v2.0`
|
|
193
197
|
]
|
|
198
|
+
// For backward compatibility
|
|
199
|
+
if (conn.connectionSettings.federatedClientId) {
|
|
200
|
+
conn.connectionSettings.FICClientId = conn.connectionSettings.federatedClientId
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (conn.connectionSettings.scopes?.length) {
|
|
204
|
+
conn.connectionSettings.scope = conn.connectionSettings.scopes?.[0]
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (conn.connectionSettings.authorityEndpoint) {
|
|
208
|
+
conn.connectionSettings.authority = conn.connectionSettings.authorityEndpoint
|
|
209
|
+
}
|
|
194
210
|
}
|
|
211
|
+
|
|
195
212
|
return conn
|
|
196
213
|
}
|
|
197
214
|
}
|
|
@@ -4,20 +4,30 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { ConfidentialClientApplication, LogLevel, ManagedIdentityApplication, NodeSystemOptions } from '@azure/msal-node'
|
|
7
|
-
import
|
|
8
|
-
import { AuthConfiguration, resolveAuthority as resolveAuthorityUtil } from './authConfiguration'
|
|
7
|
+
import { AuthConfiguration, AuthType, resolveAuthority as resolveAuthorityUtil } from './authConfiguration'
|
|
9
8
|
import { AuthProvider } from './authProvider'
|
|
10
9
|
import { debug, trace } from '@microsoft/agents-telemetry'
|
|
11
|
-
import {
|
|
10
|
+
import { randomUUID } from 'crypto'
|
|
12
11
|
import { MemoryCache } from './MemoryCache'
|
|
13
12
|
import jwt from 'jsonwebtoken'
|
|
14
13
|
|
|
15
14
|
import fs from 'fs'
|
|
16
15
|
import crypto from 'crypto'
|
|
17
16
|
import { AuthenticationTraceDefinitions } from '../observability'
|
|
17
|
+
import { ExceptionHelper } from '@microsoft/agents-activity'
|
|
18
|
+
import { Errors } from '../errorHelper'
|
|
18
19
|
|
|
19
20
|
const audience = 'api://AzureADTokenExchange'
|
|
20
21
|
const logger = debug('agents:msal')
|
|
22
|
+
const agenticTokenRequestTimeoutMs = 30000
|
|
23
|
+
|
|
24
|
+
function isAbortError (error: unknown): error is Error {
|
|
25
|
+
return error instanceof Error && error.name === 'AbortError'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function createTokenRequestTimeoutError (timeoutMs: number): Error {
|
|
29
|
+
return ExceptionHelper.generateException(Error, Errors.TokenRequestTimeout, undefined, { timeoutMs: timeoutMs.toString() })
|
|
30
|
+
}
|
|
21
31
|
|
|
22
32
|
/**
|
|
23
33
|
* Provides tokens using MSAL.
|
|
@@ -70,34 +80,77 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
70
80
|
}
|
|
71
81
|
|
|
72
82
|
let token
|
|
73
|
-
if (authConfig.
|
|
74
|
-
record({ method:
|
|
75
|
-
logger.debug(
|
|
83
|
+
if (authConfig.authType) {
|
|
84
|
+
record({ method: authConfig.authType })
|
|
85
|
+
logger.debug(`getAccessToken via ${authConfig.authType} clientId=${authConfig.clientId} scope=${actualScope}`)
|
|
86
|
+
switch (authConfig.authType) {
|
|
87
|
+
case AuthType.WorkloadIdentity: {
|
|
88
|
+
const tokenFilePath = authConfig.federatedTokenFile ?? authConfig.WIDAssertionFile
|
|
89
|
+
if (!tokenFilePath) {
|
|
90
|
+
throw ExceptionHelper.generateException(Error, Errors.WorkloadIdentityTokenFileRequired)
|
|
91
|
+
}
|
|
92
|
+
token = await this.acquireAccessTokenViaWID(authConfig, actualScope)
|
|
93
|
+
break
|
|
94
|
+
}
|
|
95
|
+
case AuthType.FederatedCredentials:
|
|
96
|
+
if (!authConfig.federatedClientId && !authConfig.FICClientId) {
|
|
97
|
+
throw ExceptionHelper.generateException(Error, Errors.FICClientIdRequired)
|
|
98
|
+
}
|
|
99
|
+
token = await this.acquireAccessTokenViaFIC(authConfig, actualScope)
|
|
100
|
+
break
|
|
101
|
+
case AuthType.ClientSecret:
|
|
102
|
+
if (!authConfig.clientSecret) {
|
|
103
|
+
throw ExceptionHelper.generateException(Error, Errors.ClientSecretRequired)
|
|
104
|
+
}
|
|
105
|
+
token = await this.acquireAccessTokenViaSecret(authConfig, actualScope)
|
|
106
|
+
break
|
|
107
|
+
case AuthType.Certificate:
|
|
108
|
+
case AuthType.CertificateSubjectName:
|
|
109
|
+
if (!authConfig.certPemFile || !authConfig.certKeyFile) {
|
|
110
|
+
throw ExceptionHelper.generateException(Error, Errors.CertificateFilesRequired)
|
|
111
|
+
}
|
|
112
|
+
token = await this.acquireTokenWithCertificate(authConfig, actualScope)
|
|
113
|
+
break
|
|
114
|
+
case AuthType.UserManagedIdentity:
|
|
115
|
+
if (!authConfig.clientId) {
|
|
116
|
+
throw ExceptionHelper.generateException(Error, Errors.ClientIdRequiredForUserManagedIdentity)
|
|
117
|
+
}
|
|
118
|
+
token = await this.acquireTokenWithUserAssignedIdentity(authConfig, actualScope)
|
|
119
|
+
break
|
|
120
|
+
case AuthType.SystemManagedIdentity:
|
|
121
|
+
token = await this.acquireTokenWithSystemAssignedIdentity(authConfig, actualScope)
|
|
122
|
+
break
|
|
123
|
+
default:
|
|
124
|
+
throw ExceptionHelper.generateException(Error, Errors.UnsupportedAuthType, undefined, { authType: authConfig.authType })
|
|
125
|
+
}
|
|
126
|
+
} else if (authConfig.WIDAssertionFile !== undefined) {
|
|
127
|
+
record({ method: AuthType.WorkloadIdentity })
|
|
128
|
+
logger.debug('getAccessToken via method=%s clientId=%s scope=%s', AuthType.WorkloadIdentity, authConfig.clientId, actualScope)
|
|
76
129
|
token = await this.acquireAccessTokenViaWID(authConfig, actualScope)
|
|
77
|
-
} else if (authConfig.FICClientId !== undefined) {
|
|
78
|
-
record({ method:
|
|
79
|
-
logger.debug('getAccessToken via
|
|
130
|
+
} else if (authConfig.federatedClientId !== undefined || authConfig.FICClientId !== undefined) {
|
|
131
|
+
record({ method: AuthType.FederatedCredentials })
|
|
132
|
+
logger.debug('getAccessToken via method=%s clientId=%s scope=%s', AuthType.FederatedCredentials, authConfig.clientId, actualScope)
|
|
80
133
|
token = await this.acquireAccessTokenViaFIC(authConfig, actualScope)
|
|
81
134
|
} else if (authConfig.clientSecret !== undefined) {
|
|
82
|
-
record({ method:
|
|
83
|
-
logger.debug('getAccessToken via
|
|
135
|
+
record({ method: AuthType.ClientSecret })
|
|
136
|
+
logger.debug('getAccessToken via method=%s clientId=%s scope=%s', AuthType.ClientSecret, authConfig.clientId, actualScope)
|
|
84
137
|
token = await this.acquireAccessTokenViaSecret(authConfig, actualScope)
|
|
85
138
|
} else if (authConfig.certPemFile !== undefined &&
|
|
86
139
|
authConfig.certKeyFile !== undefined) {
|
|
87
|
-
record({ method:
|
|
88
|
-
logger.debug('getAccessToken via
|
|
140
|
+
record({ method: AuthType.Certificate })
|
|
141
|
+
logger.debug('getAccessToken via method=%s clientId=%s scope=%s', AuthType.Certificate, authConfig.clientId, actualScope)
|
|
89
142
|
token = await this.acquireTokenWithCertificate(authConfig, actualScope)
|
|
90
143
|
} else if (authConfig.clientSecret === undefined &&
|
|
91
144
|
authConfig.certPemFile === undefined &&
|
|
92
145
|
authConfig.certKeyFile === undefined) {
|
|
93
|
-
record({ method:
|
|
94
|
-
logger.debug('getAccessToken via
|
|
146
|
+
record({ method: AuthType.UserManagedIdentity })
|
|
147
|
+
logger.debug('getAccessToken via method=%s clientId=%s scope=%s', AuthType.UserManagedIdentity, authConfig.clientId, actualScope)
|
|
95
148
|
token = await this.acquireTokenWithUserAssignedIdentity(authConfig, actualScope)
|
|
96
149
|
} else {
|
|
97
|
-
throw
|
|
150
|
+
throw ExceptionHelper.generateException(Error, Errors.InvalidAuthConfig)
|
|
98
151
|
}
|
|
99
152
|
if (token === undefined) {
|
|
100
|
-
throw
|
|
153
|
+
throw ExceptionHelper.generateException(Error, Errors.FailedToAcquireToken)
|
|
101
154
|
}
|
|
102
155
|
|
|
103
156
|
return token
|
|
@@ -137,7 +190,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
137
190
|
const cca = new ConfidentialClientApplication({
|
|
138
191
|
auth: {
|
|
139
192
|
clientId: authConfig.clientId as string,
|
|
140
|
-
authority: `${authConfig.authority}/${authConfig.tenantId || 'botframework.com'}`,
|
|
193
|
+
authority: `${authConfig.authorityEndpoint ?? authConfig.authority}/${authConfig.tenantId || 'botframework.com'}`,
|
|
141
194
|
clientSecret: authConfig.clientSecret
|
|
142
195
|
},
|
|
143
196
|
system: this.sysOptions
|
|
@@ -174,7 +227,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
174
227
|
|
|
175
228
|
const token = await cca.acquireTokenByClientCredential({
|
|
176
229
|
scopes: ['api://AzureAdTokenExchange/.default'],
|
|
177
|
-
correlationId:
|
|
230
|
+
correlationId: randomUUID(),
|
|
178
231
|
azureRegion: this.connectionSettings?.azureRegion
|
|
179
232
|
})
|
|
180
233
|
|
|
@@ -193,16 +246,16 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
193
246
|
* @returns
|
|
194
247
|
*/
|
|
195
248
|
private resolveAuthority (tenantId?: string) : string {
|
|
196
|
-
const {
|
|
249
|
+
const { authorityEndpoint: configuredAuth, authority, tenantId: configuredTenantId } = this.connectionSettings ?? {}
|
|
197
250
|
|
|
198
251
|
if (!tenantId) {
|
|
199
252
|
// No agentic tenant override — delegate to shared utility
|
|
200
|
-
return resolveAuthorityUtil(configuredAuth, configuredTenantId)
|
|
253
|
+
return resolveAuthorityUtil(configuredAuth ?? authority, configuredTenantId)
|
|
201
254
|
}
|
|
202
255
|
|
|
203
256
|
// Agentic override: build a clean base using the override tenant, then replace any
|
|
204
257
|
// /common or GUID placeholder left in the authority (e.g. from a multi-tenant config)
|
|
205
|
-
const base = resolveAuthorityUtil(configuredAuth, tenantId)
|
|
258
|
+
const base = resolveAuthorityUtil(configuredAuth ?? authority, tenantId)
|
|
206
259
|
const guidPattern = /\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/
|
|
207
260
|
|
|
208
261
|
if (base.endsWith('/common') || guidPattern.test(base)) {
|
|
@@ -257,22 +310,42 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
257
310
|
data.client_info = '2'
|
|
258
311
|
}
|
|
259
312
|
|
|
260
|
-
const
|
|
313
|
+
const controller = new AbortController()
|
|
314
|
+
const timeoutId = setTimeout(() => {
|
|
315
|
+
controller.abort(createTokenRequestTimeoutError(agenticTokenRequestTimeoutMs))
|
|
316
|
+
}, agenticTokenRequestTimeoutMs)
|
|
317
|
+
|
|
318
|
+
const token = await fetch(
|
|
261
319
|
url,
|
|
262
|
-
data,
|
|
263
320
|
{
|
|
321
|
+
method: 'POST',
|
|
264
322
|
headers: {
|
|
265
323
|
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
|
|
266
|
-
}
|
|
324
|
+
},
|
|
325
|
+
body: new URLSearchParams(data as Record<string, string>).toString(),
|
|
326
|
+
signal: controller.signal
|
|
267
327
|
}
|
|
268
|
-
).
|
|
269
|
-
|
|
270
|
-
|
|
328
|
+
).then(async (response) => {
|
|
329
|
+
if (!response.ok) {
|
|
330
|
+
const errorBody = await response.text()
|
|
331
|
+
const error = new Error(`Token request failed with status ${response.status}: ${errorBody}`)
|
|
332
|
+
;(error as any).toJSON = () => ({ status: response.status, body: errorBody })
|
|
333
|
+
throw error
|
|
334
|
+
}
|
|
335
|
+
return response.json() as Promise<{ access_token: string, expires_in: number }>
|
|
336
|
+
}).catch((error) => {
|
|
337
|
+
const resolvedError = isAbortError(error)
|
|
338
|
+
? (controller.signal.reason instanceof Error ? controller.signal.reason : createTokenRequestTimeoutError(agenticTokenRequestTimeoutMs))
|
|
339
|
+
: error
|
|
340
|
+
logger.error('Error acquiring token: ', resolvedError.toJSON ? resolvedError.toJSON() : resolvedError)
|
|
341
|
+
throw resolvedError
|
|
342
|
+
}).finally(() => {
|
|
343
|
+
clearTimeout(timeoutId)
|
|
271
344
|
})
|
|
272
345
|
|
|
273
346
|
// capture token, expire local cache 5 minutes early
|
|
274
|
-
this._agenticTokenCache.set(cacheKey, token.
|
|
275
|
-
return token.
|
|
347
|
+
this._agenticTokenCache.set(cacheKey, token.access_token, token.expires_in - 300)
|
|
348
|
+
return token.access_token
|
|
276
349
|
}
|
|
277
350
|
|
|
278
351
|
public async getAgenticUserToken (tenantId: string, agentAppInstanceId: string, agenticUserId: string, scopes: string[]): Promise<string> {
|
|
@@ -303,12 +376,60 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
303
376
|
}
|
|
304
377
|
logger.debug('getAgenticApplicationToken clientId=%s tenantId=%s agentAppInstanceId=%s', this.connectionSettings.clientId, tenantId, agentAppInstanceId)
|
|
305
378
|
|
|
379
|
+
if (this.connectionSettings.authType === AuthType.IdentityProxyManager) {
|
|
380
|
+
let resource: string
|
|
381
|
+
if (!this.connectionSettings.idpmResource) {
|
|
382
|
+
resource = 'api://AzureAdTokenExchange/.default'
|
|
383
|
+
} else if (!URL.canParse(this.connectionSettings.idpmResource)) {
|
|
384
|
+
throw new Error('idpmResource must be a valid absolute URI')
|
|
385
|
+
} else {
|
|
386
|
+
resource = this.connectionSettings.idpmResource
|
|
387
|
+
}
|
|
388
|
+
const msiApp = new ManagedIdentityApplication({
|
|
389
|
+
managedIdentityIdParams: {
|
|
390
|
+
userAssignedClientId: this.connectionSettings.clientId
|
|
391
|
+
},
|
|
392
|
+
system: this.sysOptions
|
|
393
|
+
})
|
|
394
|
+
const tokenResult = await msiApp.acquireToken({ resource })
|
|
395
|
+
if (!tokenResult?.accessToken) {
|
|
396
|
+
throw new Error(`Failed to acquire token via IdentityProxyManager for agent instance: ${agentAppInstanceId}`)
|
|
397
|
+
}
|
|
398
|
+
logger.debug('getAgenticApplicationToken via IdentityProxyManager clientId=%s resource=%s', this.connectionSettings.clientId, resource)
|
|
399
|
+
return tokenResult.accessToken
|
|
400
|
+
}
|
|
401
|
+
|
|
306
402
|
let clientAssertion
|
|
307
403
|
|
|
308
|
-
if (this.connectionSettings.
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
404
|
+
if (this.connectionSettings.authType) {
|
|
405
|
+
switch (this.connectionSettings.authType) {
|
|
406
|
+
case AuthType.WorkloadIdentity: {
|
|
407
|
+
const tokenFilePath = this.connectionSettings.federatedTokenFile ?? this.connectionSettings.WIDAssertionFile
|
|
408
|
+
if (tokenFilePath === undefined) {
|
|
409
|
+
throw ExceptionHelper.generateException(Error, Errors.WorkloadIdentityTokenFileRequired)
|
|
410
|
+
}
|
|
411
|
+
clientAssertion = fs.readFileSync(tokenFilePath as string, 'utf8')
|
|
412
|
+
break
|
|
413
|
+
}
|
|
414
|
+
case AuthType.FederatedCredentials:
|
|
415
|
+
if (!this.connectionSettings.federatedClientId && !this.connectionSettings.FICClientId) {
|
|
416
|
+
throw ExceptionHelper.generateException(Error, Errors.FICClientIdRequired)
|
|
417
|
+
}
|
|
418
|
+
clientAssertion = await this.fetchExternalToken(this.connectionSettings.federatedClientId as string || this.connectionSettings.FICClientId as string)
|
|
419
|
+
break
|
|
420
|
+
case AuthType.Certificate:
|
|
421
|
+
case AuthType.CertificateSubjectName:
|
|
422
|
+
if (!this.connectionSettings.certPemFile || !this.connectionSettings.certKeyFile) {
|
|
423
|
+
throw ExceptionHelper.generateException(Error, Errors.CertificateFilesRequired)
|
|
424
|
+
}
|
|
425
|
+
clientAssertion = this.getAssertionFromCert(this.connectionSettings)
|
|
426
|
+
break
|
|
427
|
+
}
|
|
428
|
+
} else if (this.connectionSettings.WIDAssertionFile !== undefined) {
|
|
429
|
+
const tokenFilePath = this.connectionSettings.federatedTokenFile ?? this.connectionSettings.WIDAssertionFile
|
|
430
|
+
clientAssertion = fs.readFileSync(tokenFilePath as string, 'utf8')
|
|
431
|
+
} else if (this.connectionSettings.federatedClientId !== undefined || this.connectionSettings.FICClientId !== undefined) {
|
|
432
|
+
clientAssertion = await this.fetchExternalToken(this.connectionSettings.federatedClientId as string || this.connectionSettings.FICClientId as string)
|
|
312
433
|
} else if (this.connectionSettings.certPemFile !== undefined &&
|
|
313
434
|
this.connectionSettings.certKeyFile !== undefined) {
|
|
314
435
|
clientAssertion = this.getAssertionFromCert(this.connectionSettings)
|
|
@@ -380,7 +501,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
380
501
|
aud: `${this.resolveAuthority(authConfig.tenantId)}/oauth2/v2.0/token`,
|
|
381
502
|
iss: authConfig.clientId,
|
|
382
503
|
sub: authConfig.clientId,
|
|
383
|
-
jti:
|
|
504
|
+
jti: randomUUID(),
|
|
384
505
|
nbf: now,
|
|
385
506
|
iat: now,
|
|
386
507
|
exp: now + 600, // 10 minutes
|
|
@@ -415,6 +536,22 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
415
536
|
return token?.accessToken
|
|
416
537
|
}
|
|
417
538
|
|
|
539
|
+
/**
|
|
540
|
+
* Acquires a token using a system-assigned identity.
|
|
541
|
+
* @param authConfig The authentication configuration.
|
|
542
|
+
* @param scope The scope for the token.
|
|
543
|
+
* @returns A promise that resolves to the access token.
|
|
544
|
+
*/
|
|
545
|
+
private async acquireTokenWithSystemAssignedIdentity (authConfig: AuthConfiguration, scope: string) {
|
|
546
|
+
const mia = new ManagedIdentityApplication({
|
|
547
|
+
system: this.sysOptions
|
|
548
|
+
})
|
|
549
|
+
const token = await mia.acquireToken({
|
|
550
|
+
resource: scope
|
|
551
|
+
})
|
|
552
|
+
return token?.accessToken
|
|
553
|
+
}
|
|
554
|
+
|
|
418
555
|
/**
|
|
419
556
|
* Acquires a token using a certificate.
|
|
420
557
|
* @param authConfig The authentication configuration.
|
|
@@ -440,7 +577,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
440
577
|
const cca = new ConfidentialClientApplication({
|
|
441
578
|
auth: {
|
|
442
579
|
clientId: authConfig.clientId || '',
|
|
443
|
-
authority: `${authConfig.authority}/${authConfig.tenantId || 'botframework.com'}`,
|
|
580
|
+
authority: `${authConfig.authorityEndpoint ?? authConfig.authority}/${authConfig.tenantId || 'botframework.com'}`,
|
|
444
581
|
clientCertificate: {
|
|
445
582
|
privateKey: privateKey as string,
|
|
446
583
|
thumbprint: pubKeyObject.fingerprint.replaceAll(':', ''),
|
|
@@ -451,7 +588,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
451
588
|
})
|
|
452
589
|
const token = await cca.acquireTokenByClientCredential({
|
|
453
590
|
scopes: [`${scope}/.default`],
|
|
454
|
-
correlationId:
|
|
591
|
+
correlationId: randomUUID(),
|
|
455
592
|
azureRegion: authConfig.azureRegion
|
|
456
593
|
})
|
|
457
594
|
if (!token?.accessToken) {
|
|
@@ -470,14 +607,14 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
470
607
|
const cca = new ConfidentialClientApplication({
|
|
471
608
|
auth: {
|
|
472
609
|
clientId: authConfig.clientId as string,
|
|
473
|
-
authority: `${authConfig.authority}/${authConfig.tenantId || 'botframework.com'}`,
|
|
610
|
+
authority: `${authConfig.authorityEndpoint ?? authConfig.authority}/${authConfig.tenantId || 'botframework.com'}`,
|
|
474
611
|
clientSecret: authConfig.clientSecret
|
|
475
612
|
},
|
|
476
613
|
system: this.sysOptions
|
|
477
614
|
})
|
|
478
615
|
const token = await cca.acquireTokenByClientCredential({
|
|
479
616
|
scopes: [`${scope}/.default`],
|
|
480
|
-
correlationId:
|
|
617
|
+
correlationId: randomUUID(),
|
|
481
618
|
azureRegion: authConfig.azureRegion
|
|
482
619
|
})
|
|
483
620
|
if (!token?.accessToken) {
|
|
@@ -494,11 +631,11 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
494
631
|
*/
|
|
495
632
|
private async acquireAccessTokenViaFIC (authConfig: AuthConfiguration, scope: string) : Promise<string> {
|
|
496
633
|
const scopes = [`${scope}/.default`]
|
|
497
|
-
const clientAssertion = await this.fetchExternalToken(authConfig.FICClientId as string)
|
|
634
|
+
const clientAssertion = await this.fetchExternalToken(authConfig.federatedClientId as string || authConfig.FICClientId as string)
|
|
498
635
|
const cca = new ConfidentialClientApplication({
|
|
499
636
|
auth: {
|
|
500
637
|
clientId: authConfig.clientId as string,
|
|
501
|
-
authority: `${authConfig.authority}/${authConfig.tenantId}`,
|
|
638
|
+
authority: `${authConfig.authorityEndpoint ?? authConfig.authority}/${authConfig.tenantId}`,
|
|
502
639
|
clientAssertion
|
|
503
640
|
},
|
|
504
641
|
system: this.sysOptions
|
|
@@ -519,7 +656,8 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
519
656
|
*/
|
|
520
657
|
private async acquireAccessTokenViaWID (authConfig: AuthConfiguration, scope: string) : Promise<string> {
|
|
521
658
|
const scopes = [`${scope}/.default`]
|
|
522
|
-
const
|
|
659
|
+
const tokenFilePath = authConfig.federatedTokenFile ?? authConfig.WIDAssertionFile
|
|
660
|
+
const clientAssertion = fs.readFileSync(tokenFilePath as string, 'utf8')
|
|
523
661
|
const cca = new ConfidentialClientApplication({
|
|
524
662
|
auth: {
|
|
525
663
|
clientId: authConfig.clientId as string,
|