@microsoft/agents-hosting 1.6.1 → 1.7.0-beta.5.g67b2005119
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/README.md +16 -0
- package/dist/package.json +3 -3
- package/dist/src/agent-client/agentClient.js +4 -3
- package/dist/src/agent-client/agentClient.js.map +1 -1
- package/dist/src/agent-client/agentResponseHandler.d.ts +25 -6
- package/dist/src/agent-client/agentResponseHandler.js +16 -55
- package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
- package/dist/src/agent-client/createAgentResponseHandler.d.ts +48 -0
- package/dist/src/agent-client/createAgentResponseHandler.js +92 -0
- package/dist/src/agent-client/createAgentResponseHandler.js.map +1 -0
- package/dist/src/agent-client/index.d.ts +1 -0
- package/dist/src/agent-client/index.js +1 -0
- package/dist/src/agent-client/index.js.map +1 -1
- package/dist/src/app/adaptiveCards/activityValueParsers.js +2 -1
- package/dist/src/app/adaptiveCards/activityValueParsers.js.map +1 -1
- package/dist/src/app/adaptiveCards/adaptiveCardsActions.js +13 -12
- package/dist/src/app/adaptiveCards/adaptiveCardsActions.js.map +1 -1
- package/dist/src/app/agentApplication.js +8 -8
- package/dist/src/app/agentApplication.js.map +1 -1
- package/dist/src/app/streaming/streamingResponse.d.ts +11 -0
- package/dist/src/app/streaming/streamingResponse.js +23 -2
- package/dist/src/app/streaming/streamingResponse.js.map +1 -1
- package/dist/src/app/turnState.d.ts +0 -1
- package/dist/src/app/turnState.js +15 -14
- package/dist/src/app/turnState.js.map +1 -1
- package/dist/src/app/turnStateProperty.js +4 -2
- package/dist/src/app/turnStateProperty.js.map +1 -1
- package/dist/src/auth/MemoryCache.d.ts +2 -1
- package/dist/src/auth/MemoryCache.js +7 -1
- package/dist/src/auth/MemoryCache.js.map +1 -1
- package/dist/src/auth/authConfiguration.d.ts +1 -1
- package/dist/src/auth/authConfiguration.js +41 -4
- package/dist/src/auth/authConfiguration.js.map +1 -1
- package/dist/src/auth/authConstants.d.ts +7 -7
- package/dist/src/auth/authConstants.js.map +1 -1
- package/dist/src/auth/connectionManager.d.ts +92 -0
- package/dist/src/auth/{msalConnectionManager.js → connectionManager.js} +50 -48
- package/dist/src/auth/connectionManager.js.map +1 -0
- package/dist/src/auth/index.d.ts +5 -3
- package/dist/src/auth/index.js +5 -3
- package/dist/src/auth/index.js.map +1 -1
- package/dist/src/auth/jwt-middleware.d.ts +8 -2
- package/dist/src/auth/jwt-middleware.js +116 -7
- package/dist/src/auth/jwt-middleware.js.map +1 -1
- package/dist/src/auth/msal/msalConnectionManager.d.ts +17 -0
- package/dist/src/auth/msal/msalConnectionManager.js +50 -0
- package/dist/src/auth/msal/msalConnectionManager.js.map +1 -0
- package/dist/src/auth/msal/msalConnectionSettings.d.ts +68 -0
- package/dist/src/auth/msal/msalConnectionSettings.js +7 -0
- package/dist/src/auth/msal/msalConnectionSettings.js.map +1 -0
- package/dist/src/auth/{msalTokenCredential.d.ts → msal/msalTokenCredential.d.ts} +1 -1
- package/dist/src/auth/{msalTokenCredential.js → msal/msalTokenCredential.js} +2 -2
- package/dist/src/auth/msal/msalTokenCredential.js.map +1 -0
- package/dist/src/auth/{msalTokenProvider.d.ts → msal/msalTokenProvider.d.ts} +23 -3
- package/dist/src/auth/{msalTokenProvider.js → msal/msalTokenProvider.js} +280 -176
- package/dist/src/auth/msal/msalTokenProvider.js.map +1 -0
- package/dist/src/auth/settings.d.ts +142 -133
- package/dist/src/auth/settings.js +49 -5
- package/dist/src/auth/settings.js.map +1 -1
- package/dist/src/auth/sidecar/sidecarAuthProvider.d.ts +74 -0
- package/dist/src/auth/sidecar/sidecarAuthProvider.js +181 -0
- package/dist/src/auth/sidecar/sidecarAuthProvider.js.map +1 -0
- package/dist/src/auth/sidecar/sidecarConnectionSettings.d.ts +65 -0
- package/dist/src/auth/sidecar/sidecarConnectionSettings.js +7 -0
- package/dist/src/auth/sidecar/sidecarConnectionSettings.js.map +1 -0
- package/dist/src/auth/sidecar/sidecarHttpClient.d.ts +95 -0
- package/dist/src/auth/sidecar/sidecarHttpClient.js +406 -0
- package/dist/src/auth/sidecar/sidecarHttpClient.js.map +1 -0
- package/dist/src/auth/sidecar/sidecarModels.d.ts +110 -0
- package/dist/src/auth/sidecar/sidecarModels.js +48 -0
- package/dist/src/auth/sidecar/sidecarModels.js.map +1 -0
- package/dist/src/auth/sidecar/sidecarTokenExpiry.d.ts +13 -0
- package/dist/src/auth/sidecar/sidecarTokenExpiry.js +39 -0
- package/dist/src/auth/sidecar/sidecarTokenExpiry.js.map +1 -0
- package/dist/src/baseAdapter.js +3 -1
- package/dist/src/baseAdapter.js.map +1 -1
- package/dist/src/cloudAdapter.d.ts +2 -2
- package/dist/src/cloudAdapter.js +11 -11
- package/dist/src/cloudAdapter.js.map +1 -1
- package/dist/src/createCloudAdapter.d.ts +40 -0
- package/dist/src/createCloudAdapter.js +44 -0
- package/dist/src/createCloudAdapter.js.map +1 -0
- package/dist/src/errorHelper.js +302 -79
- package/dist/src/errorHelper.js.map +1 -1
- package/dist/src/headerPropagation.js +3 -1
- package/dist/src/headerPropagation.js.map +1 -1
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +4 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/interfaces/index.d.ts +5 -0
- package/dist/src/interfaces/index.js +22 -0
- package/dist/src/interfaces/index.js.map +1 -0
- package/dist/src/interfaces/webResponse.d.ts +41 -0
- package/dist/src/interfaces/webResponse.js +7 -0
- package/dist/src/interfaces/webResponse.js.map +1 -0
- package/dist/src/middlewareSet.d.ts +0 -1
- package/dist/src/middlewareSet.js +4 -1
- package/dist/src/middlewareSet.js.map +1 -1
- package/dist/src/oauth/userTokenClient.d.ts +12 -0
- package/dist/src/oauth/userTokenClient.js +30 -9
- package/dist/src/oauth/userTokenClient.js.map +1 -1
- package/dist/src/state/conversationState.js +4 -2
- package/dist/src/state/conversationState.js.map +1 -1
- package/dist/src/state/userState.js +4 -2
- package/dist/src/state/userState.js.map +1 -1
- package/dist/src/storage/memoryStorage.js +5 -3
- package/dist/src/storage/memoryStorage.js.map +1 -1
- package/dist/src/transcript/consoleTranscriptLogger.js +3 -1
- package/dist/src/transcript/consoleTranscriptLogger.js.map +1 -1
- package/dist/src/transcript/fileTranscriptLogger.js +5 -4
- package/dist/src/transcript/fileTranscriptLogger.js.map +1 -1
- package/dist/src/transcript/transcriptLoggerMiddleware.js +2 -1
- package/dist/src/transcript/transcriptLoggerMiddleware.js.map +1 -1
- package/dist/src/turnContext.js +2 -1
- package/dist/src/turnContext.js.map +1 -1
- package/package.json +3 -3
- package/src/agent-client/agentClient.ts +5 -4
- package/src/agent-client/agentResponseHandler.ts +43 -67
- package/src/agent-client/createAgentResponseHandler.ts +133 -0
- package/src/agent-client/index.ts +1 -0
- package/src/app/adaptiveCards/activityValueParsers.ts +3 -2
- package/src/app/adaptiveCards/adaptiveCardsActions.ts +5 -5
- package/src/app/agentApplication.ts +8 -16
- package/src/app/streaming/streamingResponse.ts +26 -3
- package/src/app/turnState.ts +15 -14
- package/src/app/turnStateProperty.ts +4 -2
- package/src/auth/MemoryCache.ts +7 -1
- package/src/auth/authConfiguration.ts +41 -6
- package/src/auth/authConstants.ts +7 -7
- package/src/auth/{msalConnectionManager.ts → connectionManager.ts} +65 -61
- package/src/auth/index.ts +5 -3
- package/src/auth/jwt-middleware.ts +118 -9
- package/src/auth/msal/msalConnectionManager.ts +55 -0
- package/src/auth/msal/msalConnectionSettings.ts +79 -0
- package/src/auth/{msalTokenCredential.ts → msal/msalTokenCredential.ts} +2 -1
- package/src/auth/{msalTokenProvider.ts → msal/msalTokenProvider.ts} +353 -172
- package/src/auth/settings.ts +131 -76
- package/src/auth/sidecar/sidecarAuthProvider.ts +234 -0
- package/src/auth/sidecar/sidecarConnectionSettings.ts +72 -0
- package/src/auth/sidecar/sidecarHttpClient.ts +443 -0
- package/src/auth/sidecar/sidecarModels.ts +153 -0
- package/src/auth/sidecar/sidecarTokenExpiry.ts +35 -0
- package/src/baseAdapter.ts +3 -2
- package/src/cloudAdapter.ts +13 -13
- package/src/createCloudAdapter.ts +56 -0
- package/src/errorHelper.ts +354 -89
- package/src/headerPropagation.ts +4 -1
- package/src/index.ts +3 -1
- package/src/interfaces/index.ts +6 -0
- package/src/interfaces/webResponse.ts +44 -0
- package/src/middlewareSet.ts +3 -1
- package/src/oauth/userTokenClient.ts +46 -11
- package/src/state/conversationState.ts +4 -3
- package/src/state/userState.ts +4 -3
- package/src/storage/memoryStorage.ts +5 -3
- package/src/transcript/consoleTranscriptLogger.ts +3 -2
- package/src/transcript/fileTranscriptLogger.ts +6 -5
- package/src/transcript/transcriptLoggerMiddleware.ts +3 -2
- package/src/turnContext.ts +3 -2
- package/dist/src/auth/msalConnectionManager.d.ts +0 -64
- package/dist/src/auth/msalConnectionManager.js.map +0 -1
- package/dist/src/auth/msalTokenCredential.js.map +0 -1
- package/dist/src/auth/msalTokenProvider.js.map +0 -1
package/src/auth/settings.ts
CHANGED
|
@@ -4,13 +4,29 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { debug } from '@microsoft/agents-telemetry'
|
|
7
|
-
import
|
|
7
|
+
import { ExceptionHelper } from '@microsoft/agents-activity'
|
|
8
|
+
import { Errors } from '../errorHelper'
|
|
9
|
+
import type { MsalConnectionSettings } from './msal/msalConnectionSettings'
|
|
10
|
+
import type { SidecarConnectionSettings } from './sidecar/sidecarConnectionSettings'
|
|
11
|
+
|
|
12
|
+
export type { MsalConnectionSettings } from './msal/msalConnectionSettings'
|
|
13
|
+
export type { SidecarConnectionSettings } from './sidecar/sidecarConnectionSettings'
|
|
8
14
|
|
|
9
15
|
const logger = debug('agents:authConfiguration')
|
|
10
16
|
|
|
11
17
|
const DEFAULT_CONNECTION = 'serviceConnection'
|
|
12
18
|
const AUTHORITY_DEFAULT = 'https://login.microsoftonline.com'
|
|
13
19
|
|
|
20
|
+
/**
|
|
21
|
+
* A single entry in the connections map used to route an inbound activity
|
|
22
|
+
* (matched by audience and/or serviceUrl) to a named connection.
|
|
23
|
+
*/
|
|
24
|
+
export interface ConnectionMapItem {
|
|
25
|
+
serviceUrl: string
|
|
26
|
+
audience?: string
|
|
27
|
+
connection: string
|
|
28
|
+
}
|
|
29
|
+
|
|
14
30
|
export const DEFAULT_CONNECTION_MAP: ConnectionMapItem = { serviceUrl: '*', connection: DEFAULT_CONNECTION }
|
|
15
31
|
|
|
16
32
|
export type ConnectionKeys = keyof Omit<AuthConfiguration, 'connections' | 'connectionsMap'>
|
|
@@ -53,8 +69,14 @@ export function applyDefaultSettings (config: AuthConfiguration) {
|
|
|
53
69
|
settings.authority = settings.authorityEndpoint
|
|
54
70
|
}
|
|
55
71
|
|
|
72
|
+
// .NET parity alias: keep altBlueprintConnectionName and alternateBlueprintConnectionName in sync.
|
|
73
|
+
settings.altBlueprintConnectionName ??= settings.alternateBlueprintConnectionName
|
|
74
|
+
if (settings.altBlueprintConnectionName) {
|
|
75
|
+
settings.alternateBlueprintConnectionName = settings.altBlueprintConnectionName
|
|
76
|
+
}
|
|
77
|
+
|
|
56
78
|
if (!settings.clientId && process.env.NODE_ENV?.toLowerCase() === 'production') {
|
|
57
|
-
throw
|
|
79
|
+
throw ExceptionHelper.generateException(Error, Errors.ClientIdRequiredInProduction)
|
|
58
80
|
}
|
|
59
81
|
|
|
60
82
|
const defaultConnections = settings.connections?.size
|
|
@@ -171,9 +193,16 @@ function getDefaultIssuers (tenantId: string, authority: string) : string[] {
|
|
|
171
193
|
}
|
|
172
194
|
|
|
173
195
|
/**
|
|
174
|
-
*
|
|
196
|
+
* Connection-level settings common to every authentication provider.
|
|
197
|
+
*
|
|
198
|
+
* @remarks
|
|
199
|
+
* Mirrors the .NET `Microsoft.Agents.Authentication.ConnectionSettingsBase` abstract class: these are
|
|
200
|
+
* the credential-agnostic properties shared by all connection types. Provider-specific settings
|
|
201
|
+
* extend this base (see {@link MsalConnectionSettings} for MSAL and {@link SidecarConnectionSettings}
|
|
202
|
+
* for the Entra sidecar). The active provider for a connection is selected
|
|
203
|
+
* by {@link ConnectionSettingsBase.authType | authType}; see `AuthProviderFactory`.
|
|
175
204
|
*/
|
|
176
|
-
export interface
|
|
205
|
+
export interface ConnectionSettingsBase {
|
|
177
206
|
/**
|
|
178
207
|
* The tenant ID for the authentication configuration.
|
|
179
208
|
*/
|
|
@@ -185,24 +214,9 @@ export interface AuthConfiguration {
|
|
|
185
214
|
clientId?: string
|
|
186
215
|
|
|
187
216
|
/**
|
|
188
|
-
* The
|
|
189
|
-
*/
|
|
190
|
-
clientSecret?: string
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* The path to the certificate PEM file.
|
|
194
|
-
*/
|
|
195
|
-
certPemFile?: string
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* The path to the certificate key file.
|
|
199
|
-
*/
|
|
200
|
-
certKeyFile?: string
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Indicates whether to send the X5C param or not (for SNI authentication).
|
|
217
|
+
* The authentication type for the connection.
|
|
204
218
|
*/
|
|
205
|
-
|
|
219
|
+
authType?: AuthType | string
|
|
206
220
|
|
|
207
221
|
/**
|
|
208
222
|
* A list of valid issuers for the authentication configuration.
|
|
@@ -214,13 +228,6 @@ export interface AuthConfiguration {
|
|
|
214
228
|
*/
|
|
215
229
|
connectionName?: string
|
|
216
230
|
|
|
217
|
-
/**
|
|
218
|
-
* @deprecated Use federatedClientId instead.
|
|
219
|
-
*
|
|
220
|
-
* The FIC (First-Party Integration Channel) client ID.
|
|
221
|
-
*/
|
|
222
|
-
FICClientId?: string,
|
|
223
|
-
|
|
224
231
|
/**
|
|
225
232
|
* @deprecated Use authorityEndpoint instead.
|
|
226
233
|
*
|
|
@@ -234,78 +241,89 @@ export interface AuthConfiguration {
|
|
|
234
241
|
authority?: string
|
|
235
242
|
|
|
236
243
|
/**
|
|
237
|
-
*
|
|
244
|
+
* Entra Authentication Endpoint to use.
|
|
245
|
+
*
|
|
246
|
+
* @remarks
|
|
247
|
+
* If not populated the Entra Public Cloud endpoint is assumed.
|
|
248
|
+
* This example of Public Cloud Endpoint is https://login.microsoftonline.com
|
|
249
|
+
* see also https://learn.microsoft.com/entra/identity-platform/authentication-national-cloud
|
|
238
250
|
*/
|
|
239
|
-
|
|
251
|
+
authorityEndpoint?: string
|
|
240
252
|
|
|
241
253
|
/**
|
|
242
|
-
*
|
|
254
|
+
* @deprecated Use scopes instead.
|
|
243
255
|
*/
|
|
244
|
-
|
|
256
|
+
scope?: string
|
|
245
257
|
|
|
246
258
|
/**
|
|
247
|
-
*
|
|
259
|
+
* The scopes for the authentication configuration.
|
|
248
260
|
*/
|
|
249
|
-
|
|
261
|
+
scopes?: string[]
|
|
250
262
|
|
|
251
263
|
/**
|
|
252
264
|
* An optional alternative blueprint Connection name used when constructing a connector client.
|
|
253
|
-
*/
|
|
254
|
-
altBlueprintConnectionName?: string
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* @deprecated Use `authType` set to `'WorkloadIdentity'` and `federatedTokenFile` instead.
|
|
258
265
|
*
|
|
259
|
-
*
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* The Azure region for ESTS-R regional token acquisition (e.g. 'westus', 'eastus').
|
|
265
|
-
* When set, MSAL routes token requests to the specified regional endpoint.
|
|
266
|
-
* See https://learn.microsoft.com/en-us/entra/msal/javascript/node/regional-authorities for details.
|
|
267
|
-
*/
|
|
268
|
-
azureRegion?: string
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* The authentication type for the connection.
|
|
272
|
-
*/
|
|
273
|
-
authType?: AuthType | string
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* The path to the federated token file used for Workload Identity authentication.
|
|
266
|
+
* @remarks
|
|
267
|
+
* Equivalent to the .NET `AlternateBlueprintConnectionName` connection setting. {@link alternateBlueprintConnectionName}
|
|
268
|
+
* is an alias of this property that matches the .NET name exactly; when both are provided this property takes precedence.
|
|
277
269
|
*/
|
|
278
|
-
|
|
270
|
+
altBlueprintConnectionName?: string
|
|
279
271
|
|
|
280
272
|
/**
|
|
281
|
-
*
|
|
273
|
+
* Alias of {@link altBlueprintConnectionName} named to match the .NET `AlternateBlueprintConnectionName`
|
|
274
|
+
* connection setting exactly.
|
|
282
275
|
*
|
|
283
276
|
* @remarks
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
* This setting is only meaningful when using Identity Proxy Manager (AuthType.IdentityProxyManager) for authentication.
|
|
277
|
+
* Provided for stricter .NET parity. The two properties are kept in sync during configuration normalization;
|
|
278
|
+
* {@link altBlueprintConnectionName} takes precedence when both are set.
|
|
287
279
|
*/
|
|
288
|
-
|
|
280
|
+
alternateBlueprintConnectionName?: string
|
|
281
|
+
}
|
|
289
282
|
|
|
283
|
+
/**
|
|
284
|
+
* The complete settings for a single connection, across every provider.
|
|
285
|
+
*
|
|
286
|
+
* @remarks
|
|
287
|
+
* This is the per-connection unit that an `AuthProvider` consumes: it combines the common base
|
|
288
|
+
* ({@link ConnectionSettingsBase}) with the MSAL settings ({@link MsalConnectionSettings}) and the
|
|
289
|
+
* Entra sidecar settings ({@link SidecarConnectionSettings}). The active provider for a connection is
|
|
290
|
+
* selected by `authType`, so only the subset of these properties relevant to that provider is used.
|
|
291
|
+
*
|
|
292
|
+
* Conceptually this is the consumer-facing counterpart to the {@link AuthConfiguration} *container*:
|
|
293
|
+
* each value in {@link AuthConfiguration.connections} is the settings for one connection. It parallels
|
|
294
|
+
* the .NET `IConnectionSettings` (a single connection's settings) as distinct from the connection
|
|
295
|
+
* registry. {@link AuthConfiguration} extends this type for backward compatibility (it doubles as the
|
|
296
|
+
* settings for the legacy single connection).
|
|
297
|
+
*/
|
|
298
|
+
export interface ConnectionSettings extends MsalConnectionSettings, SidecarConnectionSettings {}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Represents the authentication configuration.
|
|
302
|
+
*
|
|
303
|
+
* @remarks
|
|
304
|
+
* The agent-level authentication container. It owns the connection registry
|
|
305
|
+
* (`connections`/`connectionsMap`) and, for backward compatibility, also extends
|
|
306
|
+
* {@link ConnectionSettings} so the legacy single-connection shape (a flat config with `clientId`,
|
|
307
|
+
* `clientSecret`, etc.) keeps working — in that mode the top-level object *is* the one connection's
|
|
308
|
+
* settings. The active provider for each connection is dispatched by `authType` via
|
|
309
|
+
* `AuthProviderFactory`, so a single connection only uses the subset of these properties relevant to
|
|
310
|
+
* its provider.
|
|
311
|
+
*/
|
|
312
|
+
export interface AuthConfiguration extends ConnectionSettings {
|
|
290
313
|
/**
|
|
291
|
-
*
|
|
314
|
+
* The connection registry: a map of connection name to that connection's settings.
|
|
292
315
|
*
|
|
293
316
|
* @remarks
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*/
|
|
298
|
-
authorityEndpoint?: string
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* The federated client ID for the authentication configuration, used for workload identity federation scenarios.
|
|
317
|
+
* Each value is the {@link ConnectionSettings} for one connection (typed as {@link AuthConfiguration}
|
|
318
|
+
* for backward compatibility; only the connection-settings subset is consumed). An `AuthProvider` is
|
|
319
|
+
* created per entry by `AuthProviderFactory`, dispatched by `authType`.
|
|
302
320
|
*/
|
|
303
|
-
|
|
321
|
+
connections?: Map<string, AuthConfiguration>
|
|
304
322
|
|
|
305
323
|
/**
|
|
306
|
-
*
|
|
324
|
+
* A list of connection map items to map service URLs to connection names.
|
|
307
325
|
*/
|
|
308
|
-
|
|
326
|
+
connectionsMap?: ConnectionMapItem[]
|
|
309
327
|
}
|
|
310
328
|
|
|
311
329
|
/**
|
|
@@ -319,5 +337,42 @@ export enum AuthType {
|
|
|
319
337
|
SystemManagedIdentity = 'SystemManagedIdentity',
|
|
320
338
|
FederatedCredentials = 'FederatedCredentials',
|
|
321
339
|
WorkloadIdentity = 'WorkloadIdentity',
|
|
322
|
-
IdentityProxyManager = 'IdentityProxyManager'
|
|
340
|
+
IdentityProxyManager = 'IdentityProxyManager',
|
|
341
|
+
EntraAuthSideCar = 'EntraAuthSideCar'
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Resolves the authentication type for a given authentication configuration.
|
|
346
|
+
* @remarks
|
|
347
|
+
* The function checks various properties of the `authConfig` object to determine the appropriate authentication type.
|
|
348
|
+
* It returns a string representing the resolved authentication type or 'unknown' if it cannot be determined.
|
|
349
|
+
* @param authConfig The authentication configuration object.
|
|
350
|
+
* @returns The resolved authentication type as a string or 'unknown' if it cannot be determined.
|
|
351
|
+
*/
|
|
352
|
+
export function resolveAuthType (authConfig?: AuthConfiguration): AuthType | string {
|
|
353
|
+
if (!authConfig) {
|
|
354
|
+
return 'none'
|
|
355
|
+
}
|
|
356
|
+
if (authConfig.authType) {
|
|
357
|
+
return authConfig.authType
|
|
358
|
+
}
|
|
359
|
+
if (authConfig.WIDAssertionFile !== undefined) {
|
|
360
|
+
return AuthType.WorkloadIdentity
|
|
361
|
+
}
|
|
362
|
+
if (authConfig.federatedClientId !== undefined || authConfig.FICClientId !== undefined) {
|
|
363
|
+
return AuthType.FederatedCredentials
|
|
364
|
+
}
|
|
365
|
+
if (authConfig.clientSecret !== undefined) {
|
|
366
|
+
return AuthType.ClientSecret
|
|
367
|
+
}
|
|
368
|
+
if (authConfig.certPemFile !== undefined && authConfig.certKeyFile !== undefined) {
|
|
369
|
+
return AuthType.Certificate
|
|
370
|
+
}
|
|
371
|
+
if (authConfig.clientSecret === undefined && authConfig.certPemFile === undefined && authConfig.certKeyFile === undefined) {
|
|
372
|
+
return AuthType.UserManagedIdentity
|
|
373
|
+
}
|
|
374
|
+
if (authConfig.idpmResource !== undefined) {
|
|
375
|
+
return AuthType.IdentityProxyManager
|
|
376
|
+
}
|
|
377
|
+
return 'unknown'
|
|
323
378
|
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { debug } from '@microsoft/agents-telemetry'
|
|
7
|
+
import { ExceptionHelper } from '@microsoft/agents-activity'
|
|
8
|
+
import { Errors } from '../../errorHelper'
|
|
9
|
+
import { AuthConfiguration } from '../authConfiguration'
|
|
10
|
+
import { AuthProvider } from '../authProvider'
|
|
11
|
+
import { SidecarHttpClient } from './sidecarHttpClient'
|
|
12
|
+
import { resolveTokenExpiry } from './sidecarTokenExpiry'
|
|
13
|
+
import {
|
|
14
|
+
ResolvedSidecarConnectionSettings,
|
|
15
|
+
SidecarRequestOptions,
|
|
16
|
+
toSidecarConnectionSettings
|
|
17
|
+
} from './sidecarModels'
|
|
18
|
+
|
|
19
|
+
const logger = debug('agents:sidecar')
|
|
20
|
+
|
|
21
|
+
const GUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
22
|
+
|
|
23
|
+
// Refresh slightly ahead of the real expiry so callers never receive a token that expires mid-flight.
|
|
24
|
+
const EXPIRY_BUFFER_MS = 30 * 1000
|
|
25
|
+
|
|
26
|
+
// Hard upper bound on cached entries; protects memory when many distinct identities are served.
|
|
27
|
+
const MAX_CACHE_ENTRIES = 500
|
|
28
|
+
|
|
29
|
+
interface CachedToken {
|
|
30
|
+
token: string
|
|
31
|
+
expiresOn: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Authentication provider that delegates token acquisition to the Microsoft Entra Agent ID
|
|
36
|
+
* sidecar (agent container). This replaces MSAL at the connection layer, using the sidecar's
|
|
37
|
+
* `/AuthorizationHeaderUnauthenticated/{serviceName}` endpoint for app-only and agentic identity
|
|
38
|
+
* flows. The sidecar performs the full Blueprint→Instance→User chain internally; no MSAL exchange is
|
|
39
|
+
* performed in-process.
|
|
40
|
+
*/
|
|
41
|
+
export class SidecarAuthProvider implements AuthProvider {
|
|
42
|
+
public readonly connectionSettings?: AuthConfiguration
|
|
43
|
+
private readonly _settings: ResolvedSidecarConnectionSettings
|
|
44
|
+
private readonly _httpClient: SidecarHttpClient
|
|
45
|
+
private readonly _tokenCache: Map<string, CachedToken> = new Map()
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Creates a new {@link SidecarAuthProvider}.
|
|
49
|
+
* @param connectionSettings The connection authentication configuration.
|
|
50
|
+
*/
|
|
51
|
+
constructor (connectionSettings?: AuthConfiguration) {
|
|
52
|
+
this.connectionSettings = connectionSettings
|
|
53
|
+
this._settings = toSidecarConnectionSettings(connectionSettings)
|
|
54
|
+
|
|
55
|
+
const resolvedUrl = SidecarHttpClient.resolveBaseUrl(this._settings.sidecarBaseUrl)
|
|
56
|
+
SidecarHttpClient.validateBaseUrl(resolvedUrl, this._settings.bypassLocalNetworkRestriction)
|
|
57
|
+
this._httpClient = new SidecarHttpClient(resolvedUrl, this._settings.requestTimeout, this._settings.retryCount)
|
|
58
|
+
logger.debug('SidecarAuthProvider initialized serviceName=%s blueprintServiceName=%s', this._settings.serviceName, this._settings.blueprintServiceName)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Acquires an app-only access token from the sidecar.
|
|
63
|
+
* @param scope The scope for the token.
|
|
64
|
+
*/
|
|
65
|
+
async getAccessToken (scope: string): Promise<string>
|
|
66
|
+
/**
|
|
67
|
+
* Acquires an app-only access token from the sidecar.
|
|
68
|
+
* @param authConfig The authentication configuration. Ignored by the sidecar provider, which
|
|
69
|
+
* owns the credential and derives the token from its configured service name; accepted only to
|
|
70
|
+
* satisfy the {@link AuthProvider} overload.
|
|
71
|
+
* @param scope The scope for the token.
|
|
72
|
+
*/
|
|
73
|
+
async getAccessToken (authConfig: AuthConfiguration, scope: string): Promise<string>
|
|
74
|
+
async getAccessToken (authConfigOrScope: AuthConfiguration | string, scope?: string): Promise<string> {
|
|
75
|
+
const actualScope = typeof authConfigOrScope === 'string' ? authConfigOrScope : scope
|
|
76
|
+
const options: SidecarRequestOptions = {
|
|
77
|
+
scopes: actualScope ? [actualScope] : this._settings.scopes,
|
|
78
|
+
requestAppToken: true
|
|
79
|
+
}
|
|
80
|
+
return this.getCachedToken(this._settings.serviceName, options)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Acquires the Blueprint (agent application) token from the sidecar.
|
|
85
|
+
* @param tenantId The tenant ID.
|
|
86
|
+
* @param agentAppInstanceId The agent instance ID (from the inbound activity); maps to `AgentIdentity`.
|
|
87
|
+
*/
|
|
88
|
+
async getAgenticApplicationToken (tenantId: string, agentAppInstanceId: string): Promise<string> {
|
|
89
|
+
this.ensureConnectionSettings()
|
|
90
|
+
const options: SidecarRequestOptions = {
|
|
91
|
+
agentIdentity: agentAppInstanceId,
|
|
92
|
+
tenant: tenantId
|
|
93
|
+
}
|
|
94
|
+
return this.getCachedToken(this._settings.blueprintServiceName, options)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Acquires the autonomous agent (instance) token from the sidecar for the configured resource.
|
|
99
|
+
* @param tenantId The tenant ID.
|
|
100
|
+
* @param agentAppInstanceId The agent instance ID (from the inbound activity); maps to `AgentIdentity`.
|
|
101
|
+
*/
|
|
102
|
+
async getAgenticInstanceToken (tenantId: string, agentAppInstanceId: string): Promise<string> {
|
|
103
|
+
this.ensureConnectionSettings()
|
|
104
|
+
const options: SidecarRequestOptions = {
|
|
105
|
+
agentIdentity: agentAppInstanceId,
|
|
106
|
+
requestAppToken: true,
|
|
107
|
+
tenant: tenantId,
|
|
108
|
+
scopes: this._settings.scopes
|
|
109
|
+
}
|
|
110
|
+
return this.getCachedToken(this._settings.serviceName, options)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Acquires the agentic user token from the sidecar for the configured resource.
|
|
115
|
+
* @param tenantId The tenant ID.
|
|
116
|
+
* @param agentAppInstanceId The agent instance ID (from the inbound activity); maps to `AgentIdentity`.
|
|
117
|
+
* @param upn The agentic user identifier. A GUID is sent as `AgentUserId`; otherwise as `AgentUsername`.
|
|
118
|
+
* @param scopes The OAuth scopes to request.
|
|
119
|
+
*/
|
|
120
|
+
async getAgenticUserToken (tenantId: string, agentAppInstanceId: string, upn: string, scopes: string[]): Promise<string> {
|
|
121
|
+
this.ensureConnectionSettings()
|
|
122
|
+
const isObjectId = GUID_REGEX.test(upn ?? '')
|
|
123
|
+
const options: SidecarRequestOptions = {
|
|
124
|
+
agentIdentity: agentAppInstanceId,
|
|
125
|
+
agentUsername: isObjectId ? undefined : upn,
|
|
126
|
+
agentUserId: isObjectId ? upn : undefined,
|
|
127
|
+
tenant: tenantId,
|
|
128
|
+
scopes: scopes ?? this._settings.scopes
|
|
129
|
+
}
|
|
130
|
+
return this.getCachedToken(this._settings.serviceName, options)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* On-behalf-of token exchange — not supported by the sidecar provider in Phase 1.
|
|
135
|
+
*/
|
|
136
|
+
async acquireTokenOnBehalfOf (scopes: string[], oboAssertion: string): Promise<string>
|
|
137
|
+
async acquireTokenOnBehalfOf (authConfig: AuthConfiguration, scopes: string[], oboAssertion: string): Promise<string>
|
|
138
|
+
async acquireTokenOnBehalfOf (
|
|
139
|
+
_authConfigOrScopes: AuthConfiguration | string[],
|
|
140
|
+
_scopesOrOboAssertion?: string[] | string,
|
|
141
|
+
_oboAssertion?: string
|
|
142
|
+
): Promise<string> {
|
|
143
|
+
throw ExceptionHelper.generateException(Error, Errors.OnBehalfOfNotSupportedBySidecar)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Checks sidecar availability via the `/healthz` endpoint.
|
|
148
|
+
* @returns `true` when the sidecar is reachable and healthy.
|
|
149
|
+
*/
|
|
150
|
+
async isHealthy (): Promise<boolean> {
|
|
151
|
+
return this._httpClient.isHealthy()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private ensureConnectionSettings (): void {
|
|
155
|
+
if (!this.connectionSettings) {
|
|
156
|
+
throw ExceptionHelper.generateException(Error, Errors.SidecarConnectionSettingsRequired)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private async getCachedToken (serviceName: string, options: SidecarRequestOptions): Promise<string> {
|
|
161
|
+
const forceRefresh = options.forceRefresh === true
|
|
162
|
+
const cacheKey = SidecarAuthProvider.buildCacheKey(serviceName, options)
|
|
163
|
+
|
|
164
|
+
const cached = this.cacheGet(cacheKey, forceRefresh)
|
|
165
|
+
if (cached) {
|
|
166
|
+
return cached
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const result = await this._httpClient.getAuthorizationHeaderUnauthenticated(serviceName, options)
|
|
170
|
+
// The hosting stack always transmits the token as `Bearer {token}`. Reject any other scheme
|
|
171
|
+
// (e.g. PoP) rather than silently emitting an invalid Authorization header.
|
|
172
|
+
if (result.scheme && result.scheme.toLowerCase() !== 'bearer') {
|
|
173
|
+
throw ExceptionHelper.generateException(Error, Errors.SidecarUnsupportedAuthScheme, undefined, { scheme: result.scheme })
|
|
174
|
+
}
|
|
175
|
+
this.cacheSet(cacheKey, { token: result.token, expiresOn: resolveTokenExpiry(result.token) })
|
|
176
|
+
return result.token
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
private cacheGet (cacheKey: string, forceRefresh: boolean): string | undefined {
|
|
180
|
+
const cached = this._tokenCache.get(cacheKey)
|
|
181
|
+
if (cached) {
|
|
182
|
+
if (!forceRefresh && cached.expiresOn >= Date.now() + EXPIRY_BUFFER_MS) {
|
|
183
|
+
return cached.token
|
|
184
|
+
}
|
|
185
|
+
this._tokenCache.delete(cacheKey)
|
|
186
|
+
}
|
|
187
|
+
return undefined
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private cacheSet (cacheKey: string, token: CachedToken): void {
|
|
191
|
+
this._tokenCache.set(cacheKey, token)
|
|
192
|
+
if (this._tokenCache.size > MAX_CACHE_ENTRIES) {
|
|
193
|
+
this.pruneExpiredEntries()
|
|
194
|
+
if (this._tokenCache.size > MAX_CACHE_ENTRIES) {
|
|
195
|
+
this.evictNearestExpiry()
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private pruneExpiredEntries (): void {
|
|
201
|
+
const now = Date.now()
|
|
202
|
+
for (const [key, value] of this._tokenCache) {
|
|
203
|
+
if (value.expiresOn <= now) {
|
|
204
|
+
this._tokenCache.delete(key)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private evictNearestExpiry (): void {
|
|
210
|
+
const overflow = this._tokenCache.size - MAX_CACHE_ENTRIES
|
|
211
|
+
if (overflow <= 0) {
|
|
212
|
+
return
|
|
213
|
+
}
|
|
214
|
+
const sorted = [...this._tokenCache.entries()].sort((a, b) => a[1].expiresOn - b[1].expiresOn)
|
|
215
|
+
for (let i = 0; i < overflow; i++) {
|
|
216
|
+
this._tokenCache.delete(sorted[i][0])
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private static buildCacheKey (serviceName: string, options: SidecarRequestOptions): string {
|
|
221
|
+
const scopes = options.scopes
|
|
222
|
+
? [...new Set(options.scopes.filter((s) => s && s.trim()))].sort().join(' ')
|
|
223
|
+
: ''
|
|
224
|
+
return [
|
|
225
|
+
serviceName,
|
|
226
|
+
options.agentIdentity ?? '',
|
|
227
|
+
options.agentUsername ?? '',
|
|
228
|
+
options.agentUserId ?? '',
|
|
229
|
+
options.tenant ?? '',
|
|
230
|
+
options.requestAppToken === true ? 'app' : 'user',
|
|
231
|
+
scopes
|
|
232
|
+
].join('|')
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ConnectionSettingsBase } from '../settings'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Connection settings for the Entra Agent ID sidecar (agent container) authentication provider, used when a
|
|
10
|
+
* connection's `authType` is `'EntraAuthSideCar'`.
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* Mirrors the .NET `Microsoft.Agents.Authentication.EntraAuthSidecar.Model.SidecarConnectionSettings`
|
|
14
|
+
* class, which likewise derives from `ConnectionSettingsBase`. These are the configuration-level
|
|
15
|
+
* properties; they are normalized (with defaults applied) before use by the sidecar token provider.
|
|
16
|
+
*/
|
|
17
|
+
export interface SidecarConnectionSettings extends ConnectionSettingsBase {
|
|
18
|
+
/**
|
|
19
|
+
* Optional base URL of the Entra Agent ID sidecar (agent container).
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* Only used when `authType` is `'EntraAuthSideCar'`. Resolution order:
|
|
23
|
+
* `SIDECAR_URL` environment variable > this setting > `http://localhost:5178`.
|
|
24
|
+
* Regardless of how it is resolved, the host must be a loopback/private address
|
|
25
|
+
* unless `bypassLocalNetworkRestriction` is set.
|
|
26
|
+
*/
|
|
27
|
+
sidecarBaseUrl?: string
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The configured downstream API service name in the sidecar's DownstreamApis configuration.
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* Only used when `authType` is `'EntraAuthSideCar'`. Defaults to `'default'`.
|
|
34
|
+
*/
|
|
35
|
+
serviceName?: string
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The sidecar downstream API name used to acquire the Blueprint (agent application) token for the
|
|
39
|
+
* agentic FIC chain.
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* Only used when `authType` is `'EntraAuthSideCar'`. Defaults to `'agenticblueprint'`. This
|
|
43
|
+
* downstream API must be configured app-only with the `api://AzureAdTokenExchange/.default` scope.
|
|
44
|
+
*/
|
|
45
|
+
blueprintServiceName?: string
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* When `true`, disables the loopback/private-address safety check on the resolved sidecar base URL.
|
|
49
|
+
*
|
|
50
|
+
* @remarks
|
|
51
|
+
* UNSAFE. Leave this `false` in all normal deployments. Only enable it for a carefully validated
|
|
52
|
+
* private-network configuration where the sidecar is reachable at a non-private address that the
|
|
53
|
+
* operator explicitly trusts. Only used when `authType` is `'EntraAuthSideCar'`.
|
|
54
|
+
*/
|
|
55
|
+
bypassLocalNetworkRestriction?: boolean
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* HTTP request timeout (in milliseconds) for sidecar calls.
|
|
59
|
+
*
|
|
60
|
+
* @remarks
|
|
61
|
+
* Only used when `authType` is `'EntraAuthSideCar'`. Defaults to 30000 (30 seconds).
|
|
62
|
+
*/
|
|
63
|
+
requestTimeout?: number
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Number of retry attempts for transient sidecar failures (5xx, 408, 429, network/timeout).
|
|
67
|
+
*
|
|
68
|
+
* @remarks
|
|
69
|
+
* Only used when `authType` is `'EntraAuthSideCar'`. Defaults to 3.
|
|
70
|
+
*/
|
|
71
|
+
retryCount?: number
|
|
72
|
+
}
|