@microsoft/agents-hosting 1.6.1 → 1.7.0-beta.1.g8bcd4f11a7
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 +3 -3
- package/dist/src/app/streaming/streamingResponse.d.ts +11 -0
- package/dist/src/app/streaming/streamingResponse.js +21 -0
- package/dist/src/app/streaming/streamingResponse.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 +36 -1
- 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 +6 -0
- package/dist/src/auth/jwt-middleware.js +32 -1
- 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} +264 -160
- 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/cloudAdapter.js +1 -1
- package/dist/src/cloudAdapter.js.map +1 -1
- package/dist/src/errorHelper.js +96 -0
- package/dist/src/errorHelper.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/oauth/userTokenClient.d.ts +12 -0
- package/dist/src/oauth/userTokenClient.js +28 -8
- package/dist/src/oauth/userTokenClient.js.map +1 -1
- package/package.json +3 -3
- package/src/app/streaming/streamingResponse.ts +24 -1
- package/src/auth/MemoryCache.ts +7 -1
- package/src/auth/authConfiguration.ts +36 -3
- 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 +31 -1
- 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} +337 -156
- 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/cloudAdapter.ts +1 -1
- package/src/errorHelper.ts +110 -0
- package/src/index.ts +1 -1
- package/src/oauth/userTokenClient.ts +43 -9
- 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
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { ConnectionMapItem } from './msalConnectionManager'
|
|
7
6
|
import { debug, redactString, redactScopes, redactUrl } from '@microsoft/agents-telemetry'
|
|
8
|
-
import { loadEnvSettings, AuthConfiguration, envParser, envParserUtils, LoadEnv, applyDefaultSettings, DEFAULT_CONNECTION_MAP, ConnectionKeys, ConnectionMapKeys } from './settings'
|
|
7
|
+
import { loadEnvSettings, AuthConfiguration, envParser, envParserUtils, LoadEnv, applyDefaultSettings, DEFAULT_CONNECTION_MAP, ConnectionKeys, ConnectionMapKeys, ConnectionMapItem } from './settings'
|
|
9
8
|
|
|
10
|
-
export { type AuthConfiguration, AuthType, resolveAuthority } from './settings'
|
|
9
|
+
export { type AuthConfiguration, type ConnectionSettings, type ConnectionSettingsBase, type MsalConnectionSettings, type SidecarConnectionSettings, AuthType, resolveAuthority, type ConnectionMapItem, resolveAuthType } from './settings'
|
|
11
10
|
import { prune } from '../utils'
|
|
12
11
|
|
|
13
12
|
const logger = debug('agents:authConfiguration')
|
|
@@ -36,8 +35,15 @@ function summarizeAuthConfiguration (authConfig: AuthConfiguration) {
|
|
|
36
35
|
idpmResource: config.idpmResource ? redactUrl(config.idpmResource) : undefined,
|
|
37
36
|
connectionName: config.connectionName,
|
|
38
37
|
altBlueprintConnectionName: config.altBlueprintConnectionName,
|
|
38
|
+
alternateBlueprintConnectionName: undefined, // Alias of altBlueprintConnectionName, avoid logging duplicate info
|
|
39
39
|
azureRegion: config.azureRegion,
|
|
40
40
|
sendX5C: config.sendX5C,
|
|
41
|
+
sidecarBaseUrl: config.sidecarBaseUrl ? redactUrl(config.sidecarBaseUrl) : undefined,
|
|
42
|
+
serviceName: config.serviceName,
|
|
43
|
+
blueprintServiceName: config.blueprintServiceName,
|
|
44
|
+
bypassLocalNetworkRestriction: config.bypassLocalNetworkRestriction,
|
|
45
|
+
requestTimeout: config.requestTimeout,
|
|
46
|
+
retryCount: config.retryCount,
|
|
41
47
|
// Don't log the following properties
|
|
42
48
|
authority: undefined, // Deprecated, same as authorityEndpoint, avoid logging duplicate info
|
|
43
49
|
FICClientId: undefined, // Deprecated, same as federatedClientId, avoid logging duplicate info
|
|
@@ -82,11 +88,24 @@ const connectionsEnv = {
|
|
|
82
88
|
return { key: 'scopes', value: this.scopes(value)?.value } // redirect with single scope
|
|
83
89
|
},
|
|
84
90
|
altBlueprintConnectionName: envParserUtils.bypass,
|
|
91
|
+
alternateBlueprintConnectionName: (value) => ({ key: 'altBlueprintConnectionName', value }), // .NET parity alias
|
|
85
92
|
WIDAssertionFile: envParserUtils.bypass,
|
|
86
93
|
federatedTokenFile: envParserUtils.bypass,
|
|
87
94
|
idpmResource: envParserUtils.bypass,
|
|
88
95
|
azureRegion: envParserUtils.bypass,
|
|
89
96
|
sendX5C: (value) => ({ value: value === 'true' }),
|
|
97
|
+
sidecarBaseUrl: envParserUtils.bypass,
|
|
98
|
+
serviceName: envParserUtils.bypass,
|
|
99
|
+
blueprintServiceName: envParserUtils.bypass,
|
|
100
|
+
bypassLocalNetworkRestriction: (value) => ({ value: value === 'true' }),
|
|
101
|
+
requestTimeout: (value) => {
|
|
102
|
+
const n = parseInt(value, 10)
|
|
103
|
+
return { value: Number.isFinite(n) && n > 0 ? n : undefined }
|
|
104
|
+
},
|
|
105
|
+
retryCount: (value) => {
|
|
106
|
+
const n = parseInt(value, 10)
|
|
107
|
+
return { value: Number.isFinite(n) && n >= 0 ? n : undefined }
|
|
108
|
+
},
|
|
90
109
|
issuers (value) {
|
|
91
110
|
if (value.includes(',')) {
|
|
92
111
|
return { value: value.split(',').map(s => s.trim()).filter(Boolean) }
|
|
@@ -205,12 +224,19 @@ const legacyBotFrameworkEnv = {
|
|
|
205
224
|
authorityEndpoint: envParserUtils.redirect(connectionsEnv.parser, 'authorityEndpoint'),
|
|
206
225
|
scope: envParserUtils.redirect(connectionsEnv.parser, 'scopes'),
|
|
207
226
|
altBlueprintConnectionName: envParserUtils.redirect(connectionsEnv.parser, 'altBlueprintConnectionName'),
|
|
227
|
+
alternateBlueprintConnectionName: envParserUtils.redirect(connectionsEnv.parser, 'altBlueprintConnectionName'),
|
|
208
228
|
WIDAssertionFile: envParserUtils.redirect(connectionsEnv.parser, 'WIDAssertionFile'),
|
|
209
229
|
azureRegion: envParserUtils.redirect(connectionsEnv.parser, 'azureRegion'),
|
|
210
230
|
sendX5C: envParserUtils.redirect(connectionsEnv.parser, 'sendX5C'),
|
|
211
231
|
authType: envParserUtils.redirect(connectionsEnv.parser, 'authType'),
|
|
212
232
|
federatedTokenFile: envParserUtils.redirect(connectionsEnv.parser, 'federatedTokenFile'),
|
|
213
233
|
idpmResource: envParserUtils.redirect(connectionsEnv.parser, 'idpmResource'),
|
|
234
|
+
sidecarBaseUrl: envParserUtils.redirect(connectionsEnv.parser, 'sidecarBaseUrl'),
|
|
235
|
+
serviceName: envParserUtils.redirect(connectionsEnv.parser, 'serviceName'),
|
|
236
|
+
blueprintServiceName: envParserUtils.redirect(connectionsEnv.parser, 'blueprintServiceName'),
|
|
237
|
+
bypassLocalNetworkRestriction: envParserUtils.redirect(connectionsEnv.parser, 'bypassLocalNetworkRestriction'),
|
|
238
|
+
requestTimeout: envParserUtils.redirect(connectionsEnv.parser, 'requestTimeout'),
|
|
239
|
+
retryCount: envParserUtils.redirect(connectionsEnv.parser, 'retryCount'),
|
|
214
240
|
}),
|
|
215
241
|
process (env: LoadEnv) {
|
|
216
242
|
return legacyPrefixEnv.process.call(this, env)
|
|
@@ -233,12 +259,19 @@ const legacyPrefixEnv = {
|
|
|
233
259
|
authorityEndpoint: envParserUtils.redirect(connectionsEnv.parser, 'authorityEndpoint'),
|
|
234
260
|
scope: envParserUtils.redirect(connectionsEnv.parser, 'scopes'),
|
|
235
261
|
altBlueprintConnectionName: envParserUtils.redirect(connectionsEnv.parser, 'altBlueprintConnectionName'),
|
|
262
|
+
alternateBlueprintConnectionName: envParserUtils.redirect(connectionsEnv.parser, 'altBlueprintConnectionName'),
|
|
236
263
|
WIDAssertionFile: envParserUtils.redirect(connectionsEnv.parser, 'WIDAssertionFile'),
|
|
237
264
|
azureRegion: envParserUtils.redirect(connectionsEnv.parser, 'azureRegion'),
|
|
238
265
|
sendX5C: envParserUtils.redirect(connectionsEnv.parser, 'sendX5C'),
|
|
239
266
|
authType: envParserUtils.redirect(connectionsEnv.parser, 'authType'),
|
|
240
267
|
federatedTokenFile: envParserUtils.redirect(connectionsEnv.parser, 'federatedTokenFile'),
|
|
241
268
|
idpmResource: envParserUtils.redirect(connectionsEnv.parser, 'idpmResource'),
|
|
269
|
+
sidecarBaseUrl: envParserUtils.redirect(connectionsEnv.parser, 'sidecarBaseUrl'),
|
|
270
|
+
serviceName: envParserUtils.redirect(connectionsEnv.parser, 'serviceName'),
|
|
271
|
+
blueprintServiceName: envParserUtils.redirect(connectionsEnv.parser, 'blueprintServiceName'),
|
|
272
|
+
bypassLocalNetworkRestriction: envParserUtils.redirect(connectionsEnv.parser, 'bypassLocalNetworkRestriction'),
|
|
273
|
+
requestTimeout: envParserUtils.redirect(connectionsEnv.parser, 'requestTimeout'),
|
|
274
|
+
retryCount: envParserUtils.redirect(connectionsEnv.parser, 'retryCount'),
|
|
242
275
|
}),
|
|
243
276
|
process (env: LoadEnv, prefix?: string) {
|
|
244
277
|
const settings: Partial<AuthConfiguration> = {}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
export const ApxLocalScope = 'c16e153d-5d2b-4c21-b7f4-b05ee5d516f1/.default'
|
|
6
|
-
export const ApxDevScope = '0d94caae-b412-4943-8a68-83135ad6d35f/.default'
|
|
7
|
-
export const ApxProductionScope = '5a807f24-c9de-44ee-a3a7-329e88a00ffc/.default'
|
|
8
|
-
export const ApxGCCScope = 'c9475445-9789-4fef-9ec5-cde4a9bcd446/.default'
|
|
9
|
-
export const ApxGCCHScope = '6f669b9e-7701-4e2b-b624-82c9207fde26/.default'
|
|
10
|
-
export const ApxDoDScope = '0a069c81-8c7c-4712-886b-9c542d673ffb/.default'
|
|
11
|
-
export const ApxGallatinScope = 'bd004c8e-5acf-4c48-8570-4e7d46b2f63b/.default'
|
|
5
|
+
export const ApxLocalScope: string = 'c16e153d-5d2b-4c21-b7f4-b05ee5d516f1/.default'
|
|
6
|
+
export const ApxDevScope: string = '0d94caae-b412-4943-8a68-83135ad6d35f/.default'
|
|
7
|
+
export const ApxProductionScope: string = '5a807f24-c9de-44ee-a3a7-329e88a00ffc/.default'
|
|
8
|
+
export const ApxGCCScope: string = 'c9475445-9789-4fef-9ec5-cde4a9bcd446/.default'
|
|
9
|
+
export const ApxGCCHScope: string = '6f669b9e-7701-4e2b-b624-82c9207fde26/.default'
|
|
10
|
+
export const ApxDoDScope: string = '0a069c81-8c7c-4712-886b-9c542d673ffb/.default'
|
|
11
|
+
export const ApxGallatinScope: string = 'bd004c8e-5acf-4c48-8570-4e7d46b2f63b/.default'
|
|
@@ -3,28 +3,58 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { Activity, RoleTypes } from '@microsoft/agents-activity'
|
|
7
|
-
import { debug } from '@microsoft/agents-telemetry'
|
|
8
|
-
import { AuthConfiguration, AuthType,
|
|
6
|
+
import { Activity, ExceptionHelper, RoleTypes } from '@microsoft/agents-activity'
|
|
7
|
+
import { debug, redactString } from '@microsoft/agents-telemetry'
|
|
8
|
+
import { AuthConfiguration, AuthType, resolveAuthType } from './authConfiguration'
|
|
9
9
|
import { Connections } from './connections'
|
|
10
|
-
import {
|
|
10
|
+
import { AuthProvider } from './authProvider'
|
|
11
|
+
import { MsalTokenProvider } from './msal/msalTokenProvider'
|
|
12
|
+
import { SidecarAuthProvider } from './sidecar/sidecarAuthProvider'
|
|
11
13
|
import { JwtPayload } from 'jsonwebtoken'
|
|
14
|
+
import { Errors } from '../errorHelper'
|
|
15
|
+
import type { ConnectionMapItem } from './settings'
|
|
12
16
|
|
|
13
17
|
const logger = debug('agents:authorization:connections')
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Factory function that creates an {@link AuthProvider} instance from a connection's
|
|
21
|
+
* {@link AuthConfiguration}.
|
|
22
|
+
*/
|
|
23
|
+
export type AuthProviderFactory = (config: AuthConfiguration) => AuthProvider
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Default {@link AuthProviderFactory} that dispatches per-connection by `authType`: connections with
|
|
27
|
+
* `authType` set to `EntraAuthSideCar` use {@link SidecarAuthProvider}; all others use
|
|
28
|
+
* {@link MsalTokenProvider}.
|
|
29
|
+
* @param config The connection authentication configuration.
|
|
30
|
+
* @returns The auth provider for the connection.
|
|
31
|
+
*/
|
|
32
|
+
export const defaultAuthProviderFactory: AuthProviderFactory = (config: AuthConfiguration): AuthProvider =>
|
|
33
|
+
config?.authType === AuthType.EntraAuthSideCar
|
|
34
|
+
? new SidecarAuthProvider(config)
|
|
35
|
+
: new MsalTokenProvider(config)
|
|
20
36
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Generic, provider-agnostic connection manager. Dispatches connections to any {@link AuthProvider}
|
|
39
|
+
* implementation produced by the supplied {@link AuthProviderFactory}, while owning the
|
|
40
|
+
* provider-independent connection routing logic (audience matching, service URL dispatch,
|
|
41
|
+
* `altBlueprintConnectionName` handling, default connection resolution).
|
|
42
|
+
*/
|
|
43
|
+
export class ConnectionManager implements Connections {
|
|
44
|
+
protected _connections: Map<string, AuthProvider>
|
|
45
|
+
protected _connectionsMap: ConnectionMapItem[]
|
|
46
|
+
protected _serviceConnectionConfiguration: AuthConfiguration
|
|
47
|
+
protected static readonly DEFAULT_CONNECTION = 'serviceConnection'
|
|
26
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Creates a new {@link ConnectionManager}.
|
|
51
|
+
* @param providerFactory Factory used to instantiate an {@link AuthProvider} for each connection.
|
|
52
|
+
* @param connectionsConfigurations Map of connection names to their authentication configurations.
|
|
53
|
+
* @param connectionsMap Map items used to route activities to connections.
|
|
54
|
+
* @param configuration Fallback authentication configuration (used when the above are empty).
|
|
55
|
+
*/
|
|
27
56
|
constructor (
|
|
57
|
+
providerFactory: AuthProviderFactory = defaultAuthProviderFactory,
|
|
28
58
|
connectionsConfigurations: Map<string, AuthConfiguration> = new Map(),
|
|
29
59
|
connectionsMap: ConnectionMapItem[] = [],
|
|
30
60
|
configuration: AuthConfiguration = {}) {
|
|
@@ -35,26 +65,16 @@ export class MsalConnectionManager implements Connections {
|
|
|
35
65
|
const providedConnections = connectionsConfigurations.size > 0 ? connectionsConfigurations : (configuration.connections || new Map())
|
|
36
66
|
|
|
37
67
|
for (const [name, config] of providedConnections) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (name === MsalConnectionManager.DEFAULT_CONNECTION) {
|
|
68
|
+
this._connections.set(name, providerFactory(config))
|
|
69
|
+
if (name === ConnectionManager.DEFAULT_CONNECTION) {
|
|
41
70
|
this._serviceConnectionConfiguration = config
|
|
42
71
|
}
|
|
43
72
|
}
|
|
44
73
|
|
|
45
74
|
for (const [name, provider] of this._connections.entries()) {
|
|
46
75
|
const cfg = provider.connectionSettings
|
|
47
|
-
const authType = cfg
|
|
48
|
-
|
|
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')
|
|
57
|
-
logger.debug('connection "%s" clientId=%s tenantId=%s authType=%s', name, cfg?.clientId ?? '<none>', cfg?.tenantId ?? '<none>', authType)
|
|
76
|
+
const authType = resolveAuthType(cfg)
|
|
77
|
+
logger.debug('connection "%s" clientId=%s tenantId=%s authType=%s', name, redactString(cfg?.clientId, true) ?? '<none>', redactString(cfg?.tenantId, true) ?? '<none>', authType)
|
|
58
78
|
}
|
|
59
79
|
|
|
60
80
|
for (const item of this._connectionsMap) {
|
|
@@ -67,10 +87,10 @@ export class MsalConnectionManager implements Connections {
|
|
|
67
87
|
* @param connectionName The name of the connection.
|
|
68
88
|
* @returns The OAuth connection for the agent.
|
|
69
89
|
*/
|
|
70
|
-
getConnection (connectionName: string):
|
|
90
|
+
getConnection (connectionName: string): AuthProvider {
|
|
71
91
|
const conn = this._connections.get(connectionName)
|
|
72
92
|
if (!conn) {
|
|
73
|
-
throw
|
|
93
|
+
throw ExceptionHelper.generateException(Error, Errors.ConnectionNotFound, undefined, { connectionName })
|
|
74
94
|
}
|
|
75
95
|
return this.applyConnectionDefaults(conn)
|
|
76
96
|
}
|
|
@@ -79,9 +99,9 @@ export class MsalConnectionManager implements Connections {
|
|
|
79
99
|
* Get the default OAuth connection for the agent.
|
|
80
100
|
* @returns The default OAuth connection for the agent.
|
|
81
101
|
*/
|
|
82
|
-
getDefaultConnection ():
|
|
102
|
+
getDefaultConnection (): AuthProvider {
|
|
83
103
|
if (this._connections.size === 0) {
|
|
84
|
-
throw
|
|
104
|
+
throw ExceptionHelper.generateException(Error, Errors.NoConnectionsFoundInConfiguration)
|
|
85
105
|
}
|
|
86
106
|
|
|
87
107
|
// Return the wildcard map item instance.
|
|
@@ -91,7 +111,7 @@ export class MsalConnectionManager implements Connections {
|
|
|
91
111
|
}
|
|
92
112
|
}
|
|
93
113
|
|
|
94
|
-
const conn = this._connections.values().next().value as
|
|
114
|
+
const conn = this._connections.values().next().value as AuthProvider
|
|
95
115
|
|
|
96
116
|
return this.applyConnectionDefaults(conn)
|
|
97
117
|
}
|
|
@@ -114,9 +134,9 @@ export class MsalConnectionManager implements Connections {
|
|
|
114
134
|
* ServiceUrl is: A regex to match with, or "*" for any serviceUrl value.
|
|
115
135
|
* Connection is: A name in the 'Connections' list.
|
|
116
136
|
*/
|
|
117
|
-
getTokenProvider (identity: JwtPayload, serviceUrl: string):
|
|
137
|
+
getTokenProvider (identity: JwtPayload, serviceUrl: string): AuthProvider {
|
|
118
138
|
if (!identity) {
|
|
119
|
-
throw
|
|
139
|
+
throw ExceptionHelper.generateException(Error, Errors.IdentityRequiredForTokenProvider)
|
|
120
140
|
}
|
|
121
141
|
|
|
122
142
|
let audience
|
|
@@ -126,7 +146,7 @@ export class MsalConnectionManager implements Connections {
|
|
|
126
146
|
audience = identity.aud
|
|
127
147
|
}
|
|
128
148
|
|
|
129
|
-
if (!audience || !serviceUrl) throw
|
|
149
|
+
if (!audience || !serviceUrl) throw ExceptionHelper.generateException(Error, Errors.AudienceAndServiceUrlRequiredForTokenProvider)
|
|
130
150
|
|
|
131
151
|
if (this._connectionsMap.length === 0) {
|
|
132
152
|
logger.debug('no connectionsMap, using default connection for serviceUrl=%s', serviceUrl)
|
|
@@ -154,7 +174,7 @@ export class MsalConnectionManager implements Connections {
|
|
|
154
174
|
}
|
|
155
175
|
}
|
|
156
176
|
}
|
|
157
|
-
throw
|
|
177
|
+
throw ExceptionHelper.generateException(Error, Errors.NoConnectionForAudienceAndServiceUrl, undefined, { audience: String(audience), serviceUrl })
|
|
158
178
|
}
|
|
159
179
|
|
|
160
180
|
/**
|
|
@@ -163,7 +183,7 @@ export class MsalConnectionManager implements Connections {
|
|
|
163
183
|
* @param activity The activity.
|
|
164
184
|
* @returns The TokenProvider for the connection.
|
|
165
185
|
*/
|
|
166
|
-
getTokenProviderFromActivity (identity: JwtPayload, activity: Activity):
|
|
186
|
+
getTokenProviderFromActivity (identity: JwtPayload, activity: Activity): AuthProvider {
|
|
167
187
|
let connection = this.getTokenProvider(identity, activity.serviceUrl || '')
|
|
168
188
|
|
|
169
189
|
// This is for the case where the Agentic BlueprintId is not the same as the AppId
|
|
@@ -186,29 +206,13 @@ export class MsalConnectionManager implements Connections {
|
|
|
186
206
|
return this._serviceConnectionConfiguration
|
|
187
207
|
}
|
|
188
208
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
`${resolveAuthority(conn.connectionSettings.authorityEndpoint, conn.connectionSettings.tenantId)}/v2.0`
|
|
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
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
209
|
+
/**
|
|
210
|
+
* Applies provider-specific defaults to a resolved connection before returning it. The generic
|
|
211
|
+
* base performs no mutation; provider-specific managers may override this.
|
|
212
|
+
* @param conn The resolved auth provider.
|
|
213
|
+
* @returns The auth provider, possibly with defaults applied.
|
|
214
|
+
*/
|
|
215
|
+
protected applyConnectionDefaults (conn: AuthProvider): AuthProvider {
|
|
212
216
|
return conn
|
|
213
217
|
}
|
|
214
218
|
}
|
package/src/auth/index.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export * from './authConfiguration'
|
|
2
2
|
export * from './authConstants'
|
|
3
3
|
export * from './authProvider'
|
|
4
|
-
export * from './msalTokenProvider'
|
|
4
|
+
export * from './msal/msalTokenProvider'
|
|
5
5
|
export * from './request'
|
|
6
|
-
export * from './msalTokenCredential'
|
|
7
|
-
export * from './
|
|
6
|
+
export * from './msal/msalTokenCredential'
|
|
7
|
+
export * from './connectionManager'
|
|
8
|
+
export * from './msal/msalConnectionManager'
|
|
9
|
+
export * from './sidecar/sidecarAuthProvider'
|
|
@@ -11,6 +11,15 @@ import jwt, { JwtHeader, JwtPayload, SignCallback, GetPublicKeyOrSecret } from '
|
|
|
11
11
|
import { debug } from '@microsoft/agents-telemetry'
|
|
12
12
|
|
|
13
13
|
const logger = debug('agents:jwt-middleware')
|
|
14
|
+
const jwksClients = new Map<string, JwksClient>()
|
|
15
|
+
const maxJwksClients = 100
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Clears process-wide JWKS clients.
|
|
19
|
+
*/
|
|
20
|
+
export function clearJwksClients (): void {
|
|
21
|
+
jwksClients.clear()
|
|
22
|
+
}
|
|
14
23
|
|
|
15
24
|
/**
|
|
16
25
|
* Builds the JWKS URI for the given token issuer and auth configuration.
|
|
@@ -24,6 +33,26 @@ export function buildJwksUri (iss: string, authConfig: AuthConfiguration): strin
|
|
|
24
33
|
: `${resolveAuthority(authConfig.authorityEndpoint ?? authConfig.authority, authConfig.tenantId)}/discovery/v2.0/keys`
|
|
25
34
|
}
|
|
26
35
|
|
|
36
|
+
export function getJwksClient (jwksUri: string): JwksClient {
|
|
37
|
+
// Check if a client for this JWKS URI already exists in the cache.
|
|
38
|
+
let client = jwksClients.get(jwksUri)
|
|
39
|
+
if (!client) {
|
|
40
|
+
client = jwksRsa({ jwksUri })
|
|
41
|
+
jwksClients.set(jwksUri, client)
|
|
42
|
+
while (jwksClients.size > maxJwksClients) {
|
|
43
|
+
const oldestKey = jwksClients.keys().next().value
|
|
44
|
+
if (oldestKey === undefined) {
|
|
45
|
+
break
|
|
46
|
+
}
|
|
47
|
+
jwksClients.delete(oldestKey)
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
jwksClients.delete(jwksUri)
|
|
51
|
+
jwksClients.set(jwksUri, client)
|
|
52
|
+
}
|
|
53
|
+
return client
|
|
54
|
+
}
|
|
55
|
+
|
|
27
56
|
/**
|
|
28
57
|
* Verifies the JWT token.
|
|
29
58
|
* @param raw The raw JWT token.
|
|
@@ -55,9 +84,10 @@ const verifyToken = async (raw: string, config: AuthConfiguration): Promise<JwtP
|
|
|
55
84
|
const jwksUri = buildJwksUri(payload.iss as string, authConfig)
|
|
56
85
|
|
|
57
86
|
logger.debug(`fetching keys from ${jwksUri}`)
|
|
58
|
-
const jwksClient
|
|
87
|
+
const jwksClient = getJwksClient(jwksUri)
|
|
59
88
|
|
|
60
89
|
const getKey: GetPublicKeyOrSecret = (header: JwtHeader, callback: SignCallback) => {
|
|
90
|
+
// Retrieve the public, issuer-wide signing key from the JWKS endpoint using the kid from the token header.
|
|
61
91
|
jwksClient.getSigningKey(header.kid, (err: Error | null, key: SigningKey | undefined): void => {
|
|
62
92
|
if (err) {
|
|
63
93
|
logger.error('jwksClient.getSigningKey ', JSON.stringify(err))
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { AuthConfiguration, resolveAuthority } from '../authConfiguration'
|
|
7
|
+
import type { ConnectionMapItem } from '../settings'
|
|
8
|
+
import { AuthProvider } from '../authProvider'
|
|
9
|
+
import { ConnectionManager, defaultAuthProviderFactory } from '../connectionManager'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Connection manager backed by MSAL (and, for `EntraAuthSideCar` connections, the Entra sidecar
|
|
13
|
+
* provider). A thin convenience subclass of {@link ConnectionManager} that supplies the default
|
|
14
|
+
* provider factory and applies MSAL-specific connection defaults.
|
|
15
|
+
*/
|
|
16
|
+
export class MsalConnectionManager extends ConnectionManager {
|
|
17
|
+
constructor (
|
|
18
|
+
connectionsConfigurations: Map<string, AuthConfiguration> = new Map(),
|
|
19
|
+
connectionsMap: ConnectionMapItem[] = [],
|
|
20
|
+
configuration: AuthConfiguration = {}) {
|
|
21
|
+
super(defaultAuthProviderFactory, connectionsConfigurations, connectionsMap, configuration)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
protected applyConnectionDefaults (conn: AuthProvider): AuthProvider {
|
|
25
|
+
if (conn.connectionSettings) {
|
|
26
|
+
conn.connectionSettings.authorityEndpoint ??= conn.connectionSettings.authority || 'https://login.microsoftonline.com'
|
|
27
|
+
conn.connectionSettings.authority ??= conn.connectionSettings.authorityEndpoint
|
|
28
|
+
conn.connectionSettings.issuers ??= [
|
|
29
|
+
'https://api.botframework.com',
|
|
30
|
+
`${resolveAuthority('https://sts.windows.net', conn.connectionSettings.tenantId)}/`,
|
|
31
|
+
`${resolveAuthority(conn.connectionSettings.authorityEndpoint, conn.connectionSettings.tenantId)}/v2.0`
|
|
32
|
+
]
|
|
33
|
+
// For backward compatibility
|
|
34
|
+
if (conn.connectionSettings.federatedClientId) {
|
|
35
|
+
conn.connectionSettings.FICClientId = conn.connectionSettings.federatedClientId
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (conn.connectionSettings.scopes?.length) {
|
|
39
|
+
conn.connectionSettings.scope = conn.connectionSettings.scopes?.[0]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (conn.connectionSettings.authorityEndpoint) {
|
|
43
|
+
conn.connectionSettings.authority = conn.connectionSettings.authorityEndpoint
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// .NET parity alias: keep altBlueprintConnectionName and alternateBlueprintConnectionName in sync.
|
|
47
|
+
conn.connectionSettings.altBlueprintConnectionName ??= conn.connectionSettings.alternateBlueprintConnectionName
|
|
48
|
+
if (conn.connectionSettings.altBlueprintConnectionName) {
|
|
49
|
+
conn.connectionSettings.alternateBlueprintConnectionName = conn.connectionSettings.altBlueprintConnectionName
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return conn
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
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 MSAL-backed authentication providers (the default providers used for
|
|
10
|
+
* every {@link AuthType} except `EntraAuthSideCar`).
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* Mirrors the .NET `Microsoft.Agents.Authentication.Msal.Model.ConnectionSettings` class. Node.js uses
|
|
14
|
+
* PEM certificate files (`certPemFile`/`certKeyFile`) rather than the Windows certificate store, so the
|
|
15
|
+
* .NET `CertThumbprint`/`CertSubjectName`/`CertStoreName`/`ValidCertificateOnly` settings have no JS
|
|
16
|
+
* equivalent; all other MSAL properties map one-to-one.
|
|
17
|
+
*/
|
|
18
|
+
export interface MsalConnectionSettings extends ConnectionSettingsBase {
|
|
19
|
+
/**
|
|
20
|
+
* The client secret for the authentication configuration.
|
|
21
|
+
*/
|
|
22
|
+
clientSecret?: string
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The path to the certificate PEM file.
|
|
26
|
+
*/
|
|
27
|
+
certPemFile?: string
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The path to the certificate key file.
|
|
31
|
+
*/
|
|
32
|
+
certKeyFile?: string
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Indicates whether to send the X5C param or not (for SNI authentication).
|
|
36
|
+
*/
|
|
37
|
+
sendX5C?: boolean
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @deprecated Use federatedClientId instead.
|
|
41
|
+
*
|
|
42
|
+
* The FIC (First-Party Integration Channel) client ID.
|
|
43
|
+
*/
|
|
44
|
+
FICClientId?: string
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @deprecated Use `authType` set to `'WorkloadIdentity'` and `federatedTokenFile` instead.
|
|
48
|
+
*
|
|
49
|
+
* The path to K8s provided token.
|
|
50
|
+
*/
|
|
51
|
+
WIDAssertionFile?: string
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The Azure region for ESTS-R regional token acquisition (e.g. 'westus', 'eastus').
|
|
55
|
+
* When set, MSAL routes token requests to the specified regional endpoint.
|
|
56
|
+
* See https://learn.microsoft.com/en-us/entra/msal/javascript/node/regional-authorities for details.
|
|
57
|
+
*/
|
|
58
|
+
azureRegion?: string
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The path to the federated token file used for Workload Identity authentication.
|
|
62
|
+
*/
|
|
63
|
+
federatedTokenFile?: string
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Sets the resource URL for Identity Proxy Manager (IDPM).
|
|
67
|
+
*
|
|
68
|
+
* @remarks
|
|
69
|
+
* Set this to the appropriate resource identifier when the application is running in an environment,
|
|
70
|
+
* such as a Foundry container, that exposes Managed Identity through a container-specific IMDS endpoint.
|
|
71
|
+
* This setting is only meaningful when using Identity Proxy Manager (AuthType.IdentityProxyManager) for authentication.
|
|
72
|
+
*/
|
|
73
|
+
idpmResource?: string
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The federated client ID for the authentication configuration, used for workload identity federation scenarios.
|
|
77
|
+
*/
|
|
78
|
+
federatedClientId?: string
|
|
79
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { GetTokenOptions, TokenCredential } from '@azure/core-auth'
|
|
2
|
-
import { AuthConfiguration
|
|
2
|
+
import { AuthConfiguration } from '../authConfiguration'
|
|
3
|
+
import { MsalTokenProvider } from './msalTokenProvider'
|
|
3
4
|
import { debug } from '@microsoft/agents-telemetry'
|
|
4
5
|
|
|
5
6
|
const logger = debug('agents:msal')
|