@microsoft/agents-hosting 1.8.1 → 1.9.0-beta.18.g6b8111bba5
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 +179 -9
- package/dist/package.json +4 -4
- package/dist/src/app/agentApplication.d.ts +3 -3
- package/dist/src/app/agentApplication.js +6 -16
- package/dist/src/app/agentApplication.js.map +1 -1
- package/dist/src/app/agentApplicationOptions.d.ts +6 -0
- package/dist/src/app/auth/authorization.d.ts +54 -0
- package/dist/src/app/auth/authorization.js +63 -2
- package/dist/src/app/auth/authorization.js.map +1 -1
- package/dist/src/app/auth/authorizationManager.d.ts +0 -8
- package/dist/src/app/auth/authorizationManager.js +104 -178
- package/dist/src/app/auth/authorizationManager.js.map +1 -1
- package/dist/src/auth/authConfiguration.d.ts +10 -3
- package/dist/src/auth/authConfiguration.js +292 -259
- package/dist/src/auth/authConfiguration.js.map +1 -1
- package/dist/src/auth/delegatedTokenCredential.d.ts +29 -0
- package/dist/src/auth/delegatedTokenCredential.js +49 -0
- package/dist/src/auth/delegatedTokenCredential.js.map +1 -0
- package/dist/src/auth/msal/msalTokenCredential.js +1 -1
- package/dist/src/auth/msal/msalTokenCredential.js.map +1 -1
- package/dist/src/auth/settings.d.ts +8 -70
- package/dist/src/auth/settings.js +5 -67
- package/dist/src/auth/settings.js.map +1 -1
- package/dist/src/cloudAdapter.d.ts +5 -0
- package/dist/src/cloudAdapter.js +13 -103
- package/dist/src/cloudAdapter.js.map +1 -1
- package/dist/src/configuration/botFrameworkEnvironmentCompatibility.d.ts +23 -0
- package/dist/src/configuration/botFrameworkEnvironmentCompatibility.js +183 -0
- package/dist/src/configuration/botFrameworkEnvironmentCompatibility.js.map +1 -0
- package/dist/src/configuration/configuration.d.ts +83 -0
- package/dist/src/configuration/configuration.js +836 -0
- package/dist/src/configuration/configuration.js.map +1 -0
- package/dist/src/configuration/configurationSource.d.ts +57 -0
- package/dist/src/configuration/configurationSource.js +7 -0
- package/dist/src/configuration/configurationSource.js.map +1 -0
- package/dist/src/configuration/environmentConfiguration.d.ts +14 -0
- package/dist/src/configuration/environmentConfiguration.js +271 -0
- package/dist/src/configuration/environmentConfiguration.js.map +1 -0
- package/dist/src/configuration/index.d.ts +7 -0
- package/dist/src/configuration/index.js +14 -0
- package/dist/src/configuration/index.js.map +1 -0
- package/dist/src/configuration/jsonFileConfigurationSource.d.ts +15 -0
- package/dist/src/configuration/jsonFileConfigurationSource.js +58 -0
- package/dist/src/configuration/jsonFileConfigurationSource.js.map +1 -0
- package/dist/src/createCloudAdapter.d.ts +30 -5
- package/dist/src/createCloudAdapter.js +17 -10
- package/dist/src/createCloudAdapter.js.map +1 -1
- package/dist/src/errorHelper.js +90 -2
- package/dist/src/errorHelper.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/outboundHostValidator.d.ts +4 -1
- package/dist/src/outboundHostValidator.js +25 -48
- package/dist/src/outboundHostValidator.js.map +1 -1
- package/dist/src/storage/fileStorage.d.ts +5 -2
- package/dist/src/storage/fileStorage.js +41 -3
- package/dist/src/storage/fileStorage.js.map +1 -1
- package/dist/src/storage/index.d.ts +1 -0
- package/dist/src/storage/index.js +1 -0
- package/dist/src/storage/index.js.map +1 -1
- package/dist/src/storage/memoryStorage.d.ts +4 -2
- package/dist/src/storage/memoryStorage.js +32 -6
- package/dist/src/storage/memoryStorage.js.map +1 -1
- package/dist/src/storage/storage.d.ts +14 -1
- package/dist/src/storage/storageExpiry.d.ts +6 -0
- package/dist/src/storage/storageExpiry.js +20 -0
- package/dist/src/storage/storageExpiry.js.map +1 -0
- package/dist/src/utils/env.d.ts +43 -0
- package/dist/src/utils/env.js +42 -6
- package/dist/src/utils/env.js.map +1 -1
- package/dist/src/utils.d.ts +1 -0
- package/dist/src/utils.js +10 -1
- package/dist/src/utils.js.map +1 -1
- package/package.json +4 -4
- package/src/app/agentApplication.ts +11 -14
- package/src/app/agentApplicationOptions.ts +7 -0
- package/src/app/auth/authorization.ts +67 -2
- package/src/app/auth/authorizationManager.ts +126 -204
- package/src/auth/authConfiguration.ts +415 -260
- package/src/auth/delegatedTokenCredential.ts +49 -0
- package/src/auth/msal/msalTokenCredential.ts +1 -1
- package/src/auth/settings.ts +5 -82
- package/src/cloudAdapter.ts +38 -113
- package/src/configuration/botFrameworkEnvironmentCompatibility.ts +245 -0
- package/src/configuration/configuration.ts +1076 -0
- package/src/configuration/configurationSource.ts +76 -0
- package/src/configuration/environmentConfiguration.ts +377 -0
- package/src/configuration/index.ts +19 -0
- package/src/configuration/jsonFileConfigurationSource.ts +74 -0
- package/src/createCloudAdapter.ts +52 -9
- package/src/errorHelper.ts +110 -2
- package/src/index.ts +1 -0
- package/src/outboundHostValidator.ts +37 -44
- package/src/storage/fileStorage.ts +43 -5
- package/src/storage/index.ts +1 -0
- package/src/storage/memoryStorage.ts +34 -8
- package/src/storage/storage.ts +15 -1
- package/src/storage/storageExpiry.ts +21 -0
- package/src/utils/env.ts +63 -0
- package/src/utils.ts +10 -0
|
@@ -4,17 +4,27 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { debug, redactString, redactScopes, redactUrl } from '@microsoft/agents-telemetry'
|
|
7
|
-
import {
|
|
7
|
+
import { AuthConfiguration, applyDefaultSettings, DEFAULT_CONNECTION_MAP, ConnectionMapItem } from './settings'
|
|
8
8
|
|
|
9
9
|
export { type AuthConfiguration, type ConnectionSettings, type ConnectionSettingsBase, type MsalConnectionSettings, type SidecarConnectionSettings, AuthType, resolveAuthority, type ConnectionMapItem, resolveAuthType } from './settings'
|
|
10
10
|
import { prune } from '../utils'
|
|
11
|
-
import { parseBooleanEnv } from '../utils/env'
|
|
12
11
|
import { ExceptionHelper } from '@microsoft/agents-activity'
|
|
13
12
|
import { Errors } from '../errorHelper'
|
|
13
|
+
import {
|
|
14
|
+
ConfigurationContext,
|
|
15
|
+
ConfigurationLayer,
|
|
16
|
+
getConfigurationSnapshot
|
|
17
|
+
} from '../configuration/configuration'
|
|
18
|
+
import { loadModernEnvironmentConfiguration } from '../configuration/environmentConfiguration'
|
|
19
|
+
import {
|
|
20
|
+
loadBotFrameworkEnvironmentConfiguration,
|
|
21
|
+
loadBotFrameworkPrefixedEnvironmentConfiguration
|
|
22
|
+
} from '../configuration/botFrameworkEnvironmentCompatibility'
|
|
14
23
|
|
|
15
24
|
const logger = debug('agents:authConfiguration')
|
|
16
25
|
|
|
17
26
|
type NonOptional<T> = { [K in keyof Required<T>]: T[K] }
|
|
27
|
+
type ConnectionMapPatch = Partial<ConnectionMapItem>
|
|
18
28
|
|
|
19
29
|
/**
|
|
20
30
|
* Summarizes the authentication configuration for logging by redacting sensitive information and pruning undefined values. This is used to log the loaded authentication settings without exposing secrets or personally identifiable information.
|
|
@@ -66,275 +76,374 @@ function summarizeAuthConfiguration (authConfig: AuthConfiguration) {
|
|
|
66
76
|
* Environment variables for connections map should be in the format ConnectionsMap__<index>__<property>, e.g. ConnectionsMap__0__ServiceUrl, ConnectionsMap__0__Connection, etc.
|
|
67
77
|
*/
|
|
68
78
|
const connectionsEnv = {
|
|
69
|
-
connections: new Map<string, AuthConfiguration>()
|
|
70
|
-
|
|
71
|
-
authType: envParserUtils.bypass,
|
|
72
|
-
tenantId: envParserUtils.bypass,
|
|
73
|
-
clientId: envParserUtils.bypass,
|
|
74
|
-
clientSecret: envParserUtils.bypass,
|
|
75
|
-
certPemFile: envParserUtils.bypass,
|
|
76
|
-
certKeyFile: envParserUtils.bypass,
|
|
77
|
-
connectionName: envParserUtils.bypass,
|
|
78
|
-
federatedClientId: envParserUtils.bypass,
|
|
79
|
-
FICClientId (value) {
|
|
80
|
-
logger.warn('Connections__<id>__Settings__FICClientId is deprecated, please use Connections__<id>__Settings__FederatedClientId instead.')
|
|
81
|
-
return { key: 'federatedClientId', value } // redirect
|
|
82
|
-
},
|
|
83
|
-
authorityEndpoint: envParserUtils.bypass,
|
|
84
|
-
authority (value) {
|
|
85
|
-
logger.warn('Connections__<id>__Settings__Authority is deprecated, please use Connections__<id>__Settings__AuthorityEndpoint instead.')
|
|
86
|
-
return { key: 'authorityEndpoint', value } // redirect
|
|
87
|
-
},
|
|
88
|
-
scopes (value) {
|
|
89
|
-
return this.issuers(value) // scopes can be comma or space separated list, same as issuers.
|
|
90
|
-
},
|
|
91
|
-
scope (value) {
|
|
92
|
-
logger.warn('Connections__<id>__Settings__Scope is deprecated, please use Connections__<id>__Settings__Scopes instead.')
|
|
93
|
-
return { key: 'scopes', value: this.scopes(value)?.value } // redirect with single scope
|
|
94
|
-
},
|
|
95
|
-
altBlueprintConnectionName: envParserUtils.bypass,
|
|
96
|
-
alternateBlueprintConnectionName: (value) => ({ key: 'altBlueprintConnectionName', value }), // .NET parity alias
|
|
97
|
-
WIDAssertionFile: envParserUtils.bypass,
|
|
98
|
-
federatedTokenFile: envParserUtils.bypass,
|
|
99
|
-
idpmResource: envParserUtils.bypass,
|
|
100
|
-
azureRegion: envParserUtils.bypass,
|
|
101
|
-
sendX5C: (value) => ({ value: value === 'true' }),
|
|
102
|
-
msalRetryCount: (value) => {
|
|
103
|
-
const n = parseInt(value, 10)
|
|
104
|
-
return { value: Number.isFinite(n) && n >= 0 ? n : undefined }
|
|
105
|
-
},
|
|
106
|
-
sidecarBaseUrl: envParserUtils.bypass,
|
|
107
|
-
serviceName: envParserUtils.bypass,
|
|
108
|
-
blueprintServiceName: envParserUtils.bypass,
|
|
109
|
-
bypassLocalNetworkRestriction: (value) => ({ value: value === 'true' }),
|
|
110
|
-
requestTimeout: (value) => {
|
|
111
|
-
const n = parseInt(value, 10)
|
|
112
|
-
return { value: Number.isFinite(n) && n > 0 ? n : undefined }
|
|
113
|
-
},
|
|
114
|
-
retryCount: (value) => {
|
|
115
|
-
const n = parseInt(value, 10)
|
|
116
|
-
return { value: Number.isFinite(n) && n >= 0 ? n : undefined }
|
|
117
|
-
},
|
|
118
|
-
issuers (value) {
|
|
119
|
-
if (value.includes(',')) {
|
|
120
|
-
return { value: value.split(',').map(s => s.trim()).filter(Boolean) }
|
|
121
|
-
}
|
|
122
|
-
return { value: value.split(/\s+/).filter(Boolean) }
|
|
123
|
-
},
|
|
124
|
-
validateIssuer: (value) => ({ value: parseBooleanEnv(value) }),
|
|
125
|
-
}),
|
|
126
|
-
default (connections?: AuthConfiguration['connections'], connectionsMap?: AuthConfiguration['connectionsMap']) {
|
|
127
|
-
const conn = connections ?? this.connections
|
|
128
|
-
const map = connectionsMap ?? connectionsMapEnv.connectionsMap
|
|
129
|
-
const name = map?.find((item) => item.serviceUrl === '*')?.connection
|
|
130
|
-
if (!name) {
|
|
131
|
-
throw ExceptionHelper.generateException(Error, Errors.NoDefaultConnectionFound)
|
|
132
|
-
}
|
|
79
|
+
connections: new Map<string, AuthConfiguration>()
|
|
80
|
+
}
|
|
133
81
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
82
|
+
const connectionsMapEnv = {
|
|
83
|
+
connectionsMap: new Map<number, ConnectionMapPatch>(),
|
|
84
|
+
finalized: [] as ConnectionMapItem[]
|
|
85
|
+
}
|
|
138
86
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
87
|
+
const loadEnv = () => {
|
|
88
|
+
const modern = loadModernEnvironmentConfiguration()
|
|
89
|
+
connectionsEnv.connections.clear()
|
|
90
|
+
for (const connection of modern.connections.values()) {
|
|
91
|
+
connectionsEnv.connections.set(
|
|
92
|
+
connection.id,
|
|
93
|
+
{ ...connection.settings } as AuthConfiguration
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
connectionsMapEnv.connectionsMap.clear()
|
|
97
|
+
for (const [index, item] of modern.connectionsMap) {
|
|
98
|
+
connectionsMapEnv.connectionsMap.set(index, { ...item })
|
|
99
|
+
}
|
|
145
100
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
101
|
+
if (connectionsEnv.connections.size === 0) {
|
|
102
|
+
logger.warn('No connections found in configuration.')
|
|
103
|
+
}
|
|
149
104
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
105
|
+
if (connectionsMapEnv.connectionsMap.size === 0 && connectionsEnv.connections.size > 0) {
|
|
106
|
+
logger.warn('No connections map found in configuration, assuming default connection map with serviceUrl "*" for the first connection.')
|
|
107
|
+
const [key] = connectionsEnv.connections.keys()
|
|
108
|
+
connectionsMapEnv.connectionsMap.set(0, { ...DEFAULT_CONNECTION_MAP, connection: key })
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
legacyBotFrameworkSettings: configurationLayerSettings(
|
|
112
|
+
loadBotFrameworkEnvironmentConfiguration()
|
|
113
|
+
),
|
|
114
|
+
legacyPrefixSettings: configurationLayerSettings(
|
|
115
|
+
loadBotFrameworkPrefixedEnvironmentConfiguration('')
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
154
119
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
120
|
+
interface AuthOperation {
|
|
121
|
+
readonly connections?: ReadonlyMap<string, Readonly<AuthConfiguration>>
|
|
122
|
+
readonly connectionsMap?: ReadonlyMap<number, Readonly<ConnectionMapPatch>>
|
|
123
|
+
readonly flatSettings?: Readonly<AuthConfiguration>
|
|
124
|
+
readonly replaceRegistry?: boolean
|
|
125
|
+
readonly synthesizeFlatConnection?: boolean
|
|
126
|
+
readonly materializeRequestedConnection?: boolean
|
|
127
|
+
}
|
|
159
128
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
129
|
+
function externalAuthOperation (layer: ConfigurationLayer): AuthOperation {
|
|
130
|
+
return {
|
|
131
|
+
connections: new Map(
|
|
132
|
+
[...layer.connections.values()].map(connection => [connection.id, connection.settings])
|
|
133
|
+
),
|
|
134
|
+
connectionsMap: layer.connectionsMap
|
|
135
|
+
}
|
|
136
|
+
}
|
|
164
137
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
138
|
+
function configurationLayerSettings (
|
|
139
|
+
layer: ConfigurationLayer,
|
|
140
|
+
connectionName?: string
|
|
141
|
+
): AuthConfiguration {
|
|
142
|
+
const connection = connectionName
|
|
143
|
+
? layer.connections.get(connectionName.toLowerCase())
|
|
144
|
+
: layer.connections.values().next().value
|
|
145
|
+
return connection ? { ...connection.settings } as AuthConfiguration : {}
|
|
146
|
+
}
|
|
169
147
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
148
|
+
function settingsOperation (
|
|
149
|
+
settings: AuthConfiguration,
|
|
150
|
+
synthesizeFlatConnection = false,
|
|
151
|
+
materializeRequestedConnection = false
|
|
152
|
+
): AuthOperation {
|
|
153
|
+
const { connections, connectionsMap, ...flatSettings } = settings
|
|
154
|
+
return {
|
|
155
|
+
flatSettings,
|
|
156
|
+
connections,
|
|
157
|
+
connectionsMap: connectionsMap
|
|
158
|
+
? new Map(connectionsMap.map((item, index) => [index, item]))
|
|
159
|
+
: undefined,
|
|
160
|
+
synthesizeFlatConnection,
|
|
161
|
+
materializeRequestedConnection
|
|
162
|
+
}
|
|
175
163
|
}
|
|
176
164
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const parts = key.split('__')
|
|
187
|
-
const [connectionsMap, index, prop] = parts
|
|
188
|
-
|
|
189
|
-
if (connectionsMap.toUpperCase() !== 'CONNECTIONSMAP') {
|
|
190
|
-
return false
|
|
191
|
-
}
|
|
165
|
+
function registryOperation (settings: AuthConfiguration): AuthOperation {
|
|
166
|
+
return {
|
|
167
|
+
connections: settings.connections,
|
|
168
|
+
connectionsMap: settings.connectionsMap
|
|
169
|
+
? new Map(settings.connectionsMap.map((item, index) => [index, item]))
|
|
170
|
+
: undefined,
|
|
171
|
+
replaceRegistry: true
|
|
172
|
+
}
|
|
173
|
+
}
|
|
192
174
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
175
|
+
function validateDirectIssuerConfiguration (config: AuthConfiguration): void {
|
|
176
|
+
validateDirectIssuerValue(config, 'validateIssuer')
|
|
177
|
+
for (const [id, settings] of config.connections ?? []) {
|
|
178
|
+
validateDirectIssuerValue(settings, `connections.${id}.settings.validateIssuer`)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
197
181
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
182
|
+
function validateDirectIssuerValue (settings: AuthConfiguration, path: string): void {
|
|
183
|
+
if (settings.validateIssuer !== undefined && typeof settings.validateIssuer !== 'boolean') {
|
|
184
|
+
throw ExceptionHelper.generateException(
|
|
185
|
+
TypeError,
|
|
186
|
+
Errors.InvalidBooleanConfigurationValue,
|
|
187
|
+
undefined,
|
|
188
|
+
{ sourceName: 'runtime configuration', path }
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
203
192
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
193
|
+
function environmentRegistryOperation (): AuthOperation {
|
|
194
|
+
return {
|
|
195
|
+
connections: connectionsEnv.connections,
|
|
196
|
+
connectionsMap: connectionsMapEnv.connectionsMap
|
|
197
|
+
}
|
|
198
|
+
}
|
|
208
199
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
200
|
+
function environmentRouteOperation (): AuthOperation {
|
|
201
|
+
return {
|
|
202
|
+
connectionsMap: connectionsMapEnv.connectionsMap
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function applyConnectionOperation (
|
|
207
|
+
connections: Map<string, AuthConfiguration>,
|
|
208
|
+
operation: AuthOperation
|
|
209
|
+
): void {
|
|
210
|
+
if (operation.replaceRegistry) {
|
|
211
|
+
const retained = retainedConnectionIds(operation)
|
|
212
|
+
for (const id of connections.keys()) {
|
|
213
|
+
if (!retained.has(id.toLowerCase())) {
|
|
214
|
+
connections.delete(id)
|
|
215
|
+
}
|
|
212
216
|
}
|
|
217
|
+
}
|
|
213
218
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
+
for (const [id, settings] of operation.connections ?? []) {
|
|
220
|
+
const existingId = findConnectionKey(connections, id)
|
|
221
|
+
const targetId = existingId ?? id
|
|
222
|
+
connections.set(targetId, { ...connections.get(targetId), ...settings })
|
|
223
|
+
}
|
|
219
224
|
}
|
|
220
225
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const legacyBotFrameworkEnv = {
|
|
226
|
-
parser: envParser({
|
|
227
|
-
MicrosoftAppTenantId: envParserUtils.redirect(connectionsEnv.parser, 'tenantId'),
|
|
228
|
-
MicrosoftAppId: envParserUtils.redirect(connectionsEnv.parser, 'clientId'),
|
|
229
|
-
MicrosoftAppPassword: envParserUtils.redirect(connectionsEnv.parser, 'clientSecret'),
|
|
230
|
-
certPemFile: envParserUtils.redirect(connectionsEnv.parser, 'certPemFile'),
|
|
231
|
-
certKeyFile: envParserUtils.redirect(connectionsEnv.parser, 'certKeyFile'),
|
|
232
|
-
connectionName: envParserUtils.redirect(connectionsEnv.parser, 'connectionName'),
|
|
233
|
-
MicrosoftAppClientId: envParserUtils.redirect(connectionsEnv.parser, 'federatedClientId'),
|
|
234
|
-
authorityEndpoint: envParserUtils.redirect(connectionsEnv.parser, 'authorityEndpoint'),
|
|
235
|
-
scope: envParserUtils.redirect(connectionsEnv.parser, 'scopes'),
|
|
236
|
-
altBlueprintConnectionName: envParserUtils.redirect(connectionsEnv.parser, 'altBlueprintConnectionName'),
|
|
237
|
-
alternateBlueprintConnectionName: envParserUtils.redirect(connectionsEnv.parser, 'altBlueprintConnectionName'),
|
|
238
|
-
WIDAssertionFile: envParserUtils.redirect(connectionsEnv.parser, 'WIDAssertionFile'),
|
|
239
|
-
azureRegion: envParserUtils.redirect(connectionsEnv.parser, 'azureRegion'),
|
|
240
|
-
sendX5C: envParserUtils.redirect(connectionsEnv.parser, 'sendX5C'),
|
|
241
|
-
msalRetryCount: envParserUtils.redirect(connectionsEnv.parser, 'msalRetryCount'),
|
|
242
|
-
authType: envParserUtils.redirect(connectionsEnv.parser, 'authType'),
|
|
243
|
-
federatedTokenFile: envParserUtils.redirect(connectionsEnv.parser, 'federatedTokenFile'),
|
|
244
|
-
idpmResource: envParserUtils.redirect(connectionsEnv.parser, 'idpmResource'),
|
|
245
|
-
sidecarBaseUrl: envParserUtils.redirect(connectionsEnv.parser, 'sidecarBaseUrl'),
|
|
246
|
-
serviceName: envParserUtils.redirect(connectionsEnv.parser, 'serviceName'),
|
|
247
|
-
blueprintServiceName: envParserUtils.redirect(connectionsEnv.parser, 'blueprintServiceName'),
|
|
248
|
-
bypassLocalNetworkRestriction: envParserUtils.redirect(connectionsEnv.parser, 'bypassLocalNetworkRestriction'),
|
|
249
|
-
requestTimeout: envParserUtils.redirect(connectionsEnv.parser, 'requestTimeout'),
|
|
250
|
-
retryCount: envParserUtils.redirect(connectionsEnv.parser, 'retryCount'),
|
|
251
|
-
validateIssuer: envParserUtils.redirect(connectionsEnv.parser, 'validateIssuer'),
|
|
252
|
-
}),
|
|
253
|
-
process (env: LoadEnv) {
|
|
254
|
-
return legacyPrefixEnv.process.call(this, env)
|
|
255
|
-
},
|
|
226
|
+
function retainedConnectionIds (operation: AuthOperation): ReadonlySet<string> {
|
|
227
|
+
return new Set(
|
|
228
|
+
[...operation.connections?.keys() ?? []].map(id => id.toLowerCase())
|
|
229
|
+
)
|
|
256
230
|
}
|
|
257
231
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
msalRetryCount: envParserUtils.redirect(connectionsEnv.parser, 'msalRetryCount'),
|
|
279
|
-
authType: envParserUtils.redirect(connectionsEnv.parser, 'authType'),
|
|
280
|
-
federatedTokenFile: envParserUtils.redirect(connectionsEnv.parser, 'federatedTokenFile'),
|
|
281
|
-
idpmResource: envParserUtils.redirect(connectionsEnv.parser, 'idpmResource'),
|
|
282
|
-
sidecarBaseUrl: envParserUtils.redirect(connectionsEnv.parser, 'sidecarBaseUrl'),
|
|
283
|
-
serviceName: envParserUtils.redirect(connectionsEnv.parser, 'serviceName'),
|
|
284
|
-
blueprintServiceName: envParserUtils.redirect(connectionsEnv.parser, 'blueprintServiceName'),
|
|
285
|
-
bypassLocalNetworkRestriction: envParserUtils.redirect(connectionsEnv.parser, 'bypassLocalNetworkRestriction'),
|
|
286
|
-
requestTimeout: envParserUtils.redirect(connectionsEnv.parser, 'requestTimeout'),
|
|
287
|
-
retryCount: envParserUtils.redirect(connectionsEnv.parser, 'retryCount'),
|
|
288
|
-
validateIssuer: envParserUtils.redirect(connectionsEnv.parser, 'validateIssuer'),
|
|
289
|
-
}),
|
|
290
|
-
process (env: LoadEnv, prefix?: string) {
|
|
291
|
-
const settings: Partial<AuthConfiguration> = {}
|
|
292
|
-
for (const key of this.parser.keys) {
|
|
293
|
-
const k = prefix ? `${prefix}_${key}` : key
|
|
294
|
-
const envValue = env[k.toUpperCase()]
|
|
295
|
-
if (!envValue) {
|
|
296
|
-
continue
|
|
297
|
-
}
|
|
298
|
-
const result = this.parser.parse(key, envValue.value)
|
|
299
|
-
if (result.key) {
|
|
300
|
-
settings[result.key as keyof AuthConfiguration] = result.value
|
|
232
|
+
function findConnectionKey (
|
|
233
|
+
connections: ReadonlyMap<string, AuthConfiguration> | undefined,
|
|
234
|
+
requested: string | undefined
|
|
235
|
+
): string | undefined {
|
|
236
|
+
if (!connections || !requested) {
|
|
237
|
+
return undefined
|
|
238
|
+
}
|
|
239
|
+
const normalized = requested.toLowerCase()
|
|
240
|
+
return [...connections.keys()].find(id => id.toLowerCase() === normalized)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function resolveConnectionsMap (operations: readonly AuthOperation[]): Map<number, ConnectionMapPatch> {
|
|
244
|
+
const connectionsMap = new Map<number, ConnectionMapPatch>()
|
|
245
|
+
for (const operation of operations) {
|
|
246
|
+
if (operation.replaceRegistry) {
|
|
247
|
+
const retained = retainedConnectionIds(operation)
|
|
248
|
+
for (const [index, item] of connectionsMap) {
|
|
249
|
+
if (item.connection && !retained.has(item.connection.toLowerCase())) {
|
|
250
|
+
connectionsMap.delete(index)
|
|
251
|
+
}
|
|
301
252
|
}
|
|
302
253
|
}
|
|
303
|
-
|
|
304
|
-
|
|
254
|
+
for (const [index, item] of operation.connectionsMap ?? []) {
|
|
255
|
+
connectionsMap.set(index, { ...connectionsMap.get(index), ...item })
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return connectionsMap
|
|
305
259
|
}
|
|
306
260
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
return
|
|
315
|
-
|
|
316
|
-
})
|
|
261
|
+
function finalizeConnectionsMap (
|
|
262
|
+
patches: ReadonlyMap<number, Readonly<ConnectionMapPatch>>,
|
|
263
|
+
connections: ReadonlyMap<string, AuthConfiguration>,
|
|
264
|
+
synthesizeDefault = true
|
|
265
|
+
): ConnectionMapItem[] {
|
|
266
|
+
if (synthesizeDefault && patches.size === 0 && connections.size === 1) {
|
|
267
|
+
const [connection] = connections.keys()
|
|
268
|
+
return [{ ...DEFAULT_CONNECTION_MAP, connection }]
|
|
269
|
+
}
|
|
317
270
|
|
|
318
|
-
|
|
319
|
-
|
|
271
|
+
return [...patches.entries()]
|
|
272
|
+
.sort(([left], [right]) => left - right)
|
|
273
|
+
.map(([index, item]) => {
|
|
274
|
+
if (!item.serviceUrl || !item.connection) {
|
|
275
|
+
throw ExceptionHelper.generateException(
|
|
276
|
+
Error,
|
|
277
|
+
Errors.InvalidConnectionMapEntry,
|
|
278
|
+
undefined,
|
|
279
|
+
{ index: index.toString() }
|
|
280
|
+
)
|
|
281
|
+
}
|
|
282
|
+
const connection = findConnectionKey(connections, item.connection)
|
|
283
|
+
if (!connection) {
|
|
284
|
+
throw ExceptionHelper.generateException(
|
|
285
|
+
Error,
|
|
286
|
+
Errors.ConnectionNotFoundInEnvironment,
|
|
287
|
+
undefined,
|
|
288
|
+
{ connectionName: item.connection }
|
|
289
|
+
)
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
serviceUrl: item.serviceUrl,
|
|
293
|
+
connection,
|
|
294
|
+
...(item.audience === undefined ? {} : { audience: item.audience })
|
|
295
|
+
}
|
|
296
|
+
})
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function resolveAuthOperations (
|
|
300
|
+
operations: readonly AuthOperation[],
|
|
301
|
+
connectionName?: string
|
|
302
|
+
): AuthConfiguration {
|
|
303
|
+
const connections = new Map<string, AuthConfiguration>()
|
|
304
|
+
for (const operation of operations) {
|
|
305
|
+
applyConnectionOperation(connections, operation)
|
|
320
306
|
}
|
|
321
307
|
|
|
322
|
-
if (
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
308
|
+
if (
|
|
309
|
+
connections.size === 0 &&
|
|
310
|
+
operations.some(operation => operation.synthesizeFlatConnection)
|
|
311
|
+
) {
|
|
312
|
+
connections.set(DEFAULT_CONNECTION_MAP.connection, {})
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const requestedName = connectionName?.trim()
|
|
316
|
+
if (
|
|
317
|
+
requestedName &&
|
|
318
|
+
!findConnectionKey(connections, requestedName) &&
|
|
319
|
+
operations.some(operation => operation.materializeRequestedConnection)
|
|
320
|
+
) {
|
|
321
|
+
connections.set(requestedName, {})
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const requestedConnection = connections.size > 0 ? requestedName : undefined
|
|
325
|
+
const requiresDefaultRoute = operations.some(operation => operation.replaceRegistry)
|
|
326
|
+
let connectionsMap = finalizeConnectionsMap(
|
|
327
|
+
resolveConnectionsMap(operations),
|
|
328
|
+
connections,
|
|
329
|
+
!requiresDefaultRoute
|
|
330
|
+
)
|
|
331
|
+
if (connectionsMap.length === 0 && (requiresDefaultRoute || connections.size > 1)) {
|
|
332
|
+
throw ExceptionHelper.generateException(Error, Errors.NoDefaultConnectionFound)
|
|
333
|
+
}
|
|
334
|
+
const defaultConnection = connectionsMap.find(item => item.serviceUrl === '*')?.connection
|
|
335
|
+
if (connectionsMap.length > 0 && !requestedConnection && !defaultConnection) {
|
|
336
|
+
throw ExceptionHelper.generateException(Error, Errors.NoDefaultConnectionFound)
|
|
337
|
+
}
|
|
338
|
+
const selectedConnection = requestedConnection || defaultConnection || connections.keys().next().value
|
|
339
|
+
|
|
340
|
+
if (connections.size > 0 && !selectedConnection) {
|
|
341
|
+
throw ExceptionHelper.generateException(Error, Errors.NoDefaultConnectionFound)
|
|
342
|
+
}
|
|
343
|
+
const selectedConnectionKey = findConnectionKey(connections, selectedConnection)
|
|
344
|
+
if (selectedConnection && !selectedConnectionKey) {
|
|
345
|
+
throw ExceptionHelper.generateException(
|
|
346
|
+
Error,
|
|
347
|
+
Errors.ConnectionNotFoundInEnvironment,
|
|
348
|
+
undefined,
|
|
349
|
+
{ connectionName: selectedConnection }
|
|
350
|
+
)
|
|
351
|
+
}
|
|
352
|
+
if (requestedConnection) {
|
|
353
|
+
connectionsMap = [{ ...DEFAULT_CONNECTION_MAP, connection: selectedConnectionKey ?? requestedConnection }]
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (selectedConnection) {
|
|
357
|
+
const selectedSettings: AuthConfiguration = {}
|
|
358
|
+
for (const operation of operations) {
|
|
359
|
+
const operationConnectionKey = findConnectionKey(operation.connections, selectedConnection)
|
|
360
|
+
const connectionSettings = operationConnectionKey
|
|
361
|
+
? operation.connections?.get(operationConnectionKey)
|
|
362
|
+
: undefined
|
|
363
|
+
if (connectionSettings) {
|
|
364
|
+
Object.assign(selectedSettings, connectionSettings)
|
|
365
|
+
}
|
|
366
|
+
if (operation.flatSettings) {
|
|
367
|
+
Object.assign(selectedSettings, operation.flatSettings)
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const resolved = applyDefaultSettings(selectedSettings)
|
|
372
|
+
const providerSettings = { ...resolved }
|
|
373
|
+
delete providerSettings.connections
|
|
374
|
+
delete providerSettings.connectionsMap
|
|
375
|
+
connections.set(selectedConnectionKey ?? selectedConnection, providerSettings)
|
|
376
|
+
return { ...providerSettings, connections, connectionsMap }
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const flatSettings: AuthConfiguration = {}
|
|
380
|
+
for (const operation of operations) {
|
|
381
|
+
Object.assign(flatSettings, operation.flatSettings)
|
|
326
382
|
}
|
|
383
|
+
return applyDefaultSettings(flatSettings)
|
|
384
|
+
}
|
|
327
385
|
|
|
386
|
+
function environmentOperation (
|
|
387
|
+
legacySettings: AuthConfiguration,
|
|
388
|
+
connectionName?: string
|
|
389
|
+
): AuthOperation {
|
|
390
|
+
return connectionsEnv.connections.size > 0
|
|
391
|
+
? environmentRegistryOperation()
|
|
392
|
+
: settingsOperation(
|
|
393
|
+
legacySettings,
|
|
394
|
+
false,
|
|
395
|
+
Boolean(connectionName?.trim() && Object.keys(legacySettings).length > 0)
|
|
396
|
+
)
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function externalOperations (context?: ConfigurationContext) {
|
|
400
|
+
const snapshot = getConfigurationSnapshot(context)
|
|
328
401
|
return {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
402
|
+
hasAuth: (['fallback', 'overrideEnvironment', 'enforce'] as const).some(mode =>
|
|
403
|
+
snapshot[mode].connections.size > 0 ||
|
|
404
|
+
snapshot[mode].connectionsMap.size > 0
|
|
405
|
+
),
|
|
406
|
+
fallback: externalAuthOperation(snapshot.fallback),
|
|
407
|
+
overrideEnvironment: externalAuthOperation(snapshot.overrideEnvironment),
|
|
408
|
+
enforce: externalAuthOperation(snapshot.enforce)
|
|
332
409
|
}
|
|
333
410
|
}
|
|
334
411
|
|
|
412
|
+
function preserveEnvironmentRegistryIdentity (
|
|
413
|
+
result: AuthConfiguration,
|
|
414
|
+
external: ReturnType<typeof externalOperations>,
|
|
415
|
+
environmentRegistrySelected: boolean
|
|
416
|
+
): AuthConfiguration {
|
|
417
|
+
if (external.hasAuth || !environmentRegistrySelected) {
|
|
418
|
+
return result
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
for (const [id, settings] of result.connections ?? []) {
|
|
422
|
+
const environmentId = findConnectionKey(connectionsEnv.connections, id)
|
|
423
|
+
if (environmentId) {
|
|
424
|
+
connectionsEnv.connections.set(environmentId, settings)
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
connectionsMapEnv.finalized.splice(
|
|
428
|
+
0,
|
|
429
|
+
connectionsMapEnv.finalized.length,
|
|
430
|
+
...(result.connectionsMap ?? [])
|
|
431
|
+
)
|
|
432
|
+
result.connections = connectionsEnv.connections
|
|
433
|
+
result.connectionsMap = connectionsMapEnv.finalized
|
|
434
|
+
return result
|
|
435
|
+
}
|
|
436
|
+
|
|
335
437
|
// Initial load of environment variables
|
|
336
438
|
let globalEnv = loadEnv()
|
|
337
439
|
|
|
440
|
+
/**
|
|
441
|
+
* Optional host-scoped inputs used while resolving authentication settings.
|
|
442
|
+
*/
|
|
443
|
+
export interface AuthConfigurationResolutionOptions {
|
|
444
|
+
configurationContext?: ConfigurationContext
|
|
445
|
+
}
|
|
446
|
+
|
|
338
447
|
/**
|
|
339
448
|
* Loads the authentication configuration from environment variables.
|
|
340
449
|
*
|
|
@@ -361,17 +470,27 @@ let globalEnv = loadEnv()
|
|
|
361
470
|
* ```
|
|
362
471
|
*
|
|
363
472
|
*/
|
|
364
|
-
export const loadAuthConfigFromEnv = (
|
|
473
|
+
export const loadAuthConfigFromEnv = (
|
|
474
|
+
cnxName?: string,
|
|
475
|
+
options?: AuthConfigurationResolutionOptions
|
|
476
|
+
): AuthConfiguration => {
|
|
365
477
|
if (process.env.TEST_MODE === 'true') {
|
|
366
478
|
globalEnv = loadEnv()
|
|
367
479
|
}
|
|
368
480
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
481
|
+
const legacySettings = cnxName?.trim()
|
|
482
|
+
? configurationLayerSettings(
|
|
483
|
+
loadBotFrameworkPrefixedEnvironmentConfiguration(cnxName),
|
|
484
|
+
cnxName
|
|
485
|
+
)
|
|
486
|
+
: globalEnv.legacyPrefixSettings
|
|
487
|
+
const external = externalOperations(options?.configurationContext)
|
|
488
|
+
const result = preserveEnvironmentRegistryIdentity(resolveAuthOperations([
|
|
489
|
+
external.fallback,
|
|
490
|
+
environmentOperation(legacySettings, cnxName),
|
|
491
|
+
external.overrideEnvironment,
|
|
492
|
+
external.enforce
|
|
493
|
+
], cnxName), external, connectionsEnv.connections.size > 0 && !cnxName?.trim())
|
|
375
494
|
if (cnxName && !result.clientId) {
|
|
376
495
|
throw ExceptionHelper.generateException(Error, Errors.ClientIdNotFoundForConnection, undefined, { connectionName: cnxName })
|
|
377
496
|
}
|
|
@@ -398,18 +517,20 @@ export const loadAuthConfigFromEnv = (cnxName?: string): AuthConfiguration => {
|
|
|
398
517
|
* ```
|
|
399
518
|
*
|
|
400
519
|
*/
|
|
401
|
-
export const loadPrevAuthConfigFromEnv
|
|
520
|
+
export const loadPrevAuthConfigFromEnv = (
|
|
521
|
+
options?: AuthConfigurationResolutionOptions
|
|
522
|
+
): AuthConfiguration => {
|
|
402
523
|
if (process.env.TEST_MODE === 'true') {
|
|
403
524
|
globalEnv = loadEnv()
|
|
404
525
|
}
|
|
405
526
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
527
|
+
const external = externalOperations(options?.configurationContext)
|
|
528
|
+
const result = preserveEnvironmentRegistryIdentity(resolveAuthOperations([
|
|
529
|
+
external.fallback,
|
|
530
|
+
environmentOperation(globalEnv.legacyBotFrameworkSettings),
|
|
531
|
+
external.overrideEnvironment,
|
|
532
|
+
external.enforce
|
|
533
|
+
]), external, connectionsEnv.connections.size > 0)
|
|
413
534
|
|
|
414
535
|
logger.info('Legacy auth settings loaded from environment', summarizeAuthConfiguration(result), result.connectionsMap)
|
|
415
536
|
return result
|
|
@@ -439,23 +560,57 @@ export const loadPrevAuthConfigFromEnv: () => AuthConfiguration = () => {
|
|
|
439
560
|
* ```
|
|
440
561
|
*
|
|
441
562
|
*/
|
|
442
|
-
export function getAuthConfigWithDefaults (
|
|
563
|
+
export function getAuthConfigWithDefaults (
|
|
564
|
+
config?: AuthConfiguration,
|
|
565
|
+
options?: AuthConfigurationResolutionOptions
|
|
566
|
+
): AuthConfiguration {
|
|
567
|
+
if (config) {
|
|
568
|
+
validateDirectIssuerConfiguration(config)
|
|
569
|
+
}
|
|
443
570
|
if (process.env.TEST_MODE === 'true') {
|
|
444
571
|
globalEnv = loadEnv()
|
|
445
572
|
}
|
|
446
573
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
574
|
+
const external = externalOperations(options?.configurationContext)
|
|
575
|
+
const operations: AuthOperation[] = [external.fallback]
|
|
576
|
+
|
|
577
|
+
if (config?.connections?.size) {
|
|
578
|
+
operations.push(settingsOperation(globalEnv.legacyPrefixSettings))
|
|
579
|
+
if (!config.connectionsMap?.length) {
|
|
580
|
+
operations.push(environmentRouteOperation())
|
|
581
|
+
}
|
|
582
|
+
operations.push(external.overrideEnvironment)
|
|
583
|
+
operations.push(registryOperation(config))
|
|
584
|
+
} else if (connectionsEnv.connections.size > 0) {
|
|
585
|
+
if (config) {
|
|
586
|
+
operations.push(settingsOperation(globalEnv.legacyPrefixSettings))
|
|
587
|
+
}
|
|
588
|
+
operations.push(environmentRegistryOperation())
|
|
589
|
+
operations.push(external.overrideEnvironment)
|
|
450
590
|
} else {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
591
|
+
operations.push(settingsOperation(globalEnv.legacyPrefixSettings))
|
|
592
|
+
operations.push(external.overrideEnvironment)
|
|
593
|
+
if (config) {
|
|
594
|
+
operations.push(settingsOperation(config, true))
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
operations.push(external.enforce)
|
|
598
|
+
|
|
599
|
+
const result = preserveEnvironmentRegistryIdentity(
|
|
600
|
+
resolveAuthOperations(operations),
|
|
601
|
+
external,
|
|
602
|
+
!config?.connections?.size && connectionsEnv.connections.size > 0
|
|
603
|
+
)
|
|
604
|
+
const directParticipates = Boolean(config?.connections?.size) ||
|
|
605
|
+
connectionsEnv.connections.size === 0
|
|
606
|
+
if (!external.hasAuth && config && directParticipates) {
|
|
607
|
+
if (config.connections?.size) {
|
|
608
|
+
result.connections = config.connections
|
|
609
|
+
}
|
|
610
|
+
if (config.connectionsMap?.length) {
|
|
611
|
+
result.connectionsMap = config.connectionsMap
|
|
456
612
|
}
|
|
457
613
|
}
|
|
458
|
-
|
|
459
614
|
logger.info('Auth settings loaded from runtime configuration', summarizeAuthConfiguration(result), result.connectionsMap)
|
|
460
615
|
return result
|
|
461
616
|
}
|