@dbx-tools/auth 0.9.31 → 0.9.36
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 +49 -97
- package/index.ts +8 -26
- package/lib/index.d.ts +8 -26
- package/lib/index.js +6 -22
- package/lib/src/{databricks-cli.d.ts → _databricks-cli.d.ts} +3 -7
- package/lib/src/_databricks-cli.js +172 -0
- package/lib/src/_errors.d.ts +5 -0
- package/lib/src/_errors.js +10 -0
- package/lib/src/{lifecycle.d.ts → _lifecycle.d.ts} +5 -5
- package/lib/src/_lifecycle.js +214 -0
- package/lib/src/_logging.d.ts +1 -1
- package/lib/src/_logging.js +2 -2
- package/lib/src/{personal-access-token.d.ts → _personal-access-token.d.ts} +1 -1
- package/lib/src/_personal-access-token.js +30 -0
- package/lib/src/_profile-config.d.ts +43 -0
- package/lib/src/_profile-config.js +443 -0
- package/lib/src/{service-principal.d.ts → _service-principal.d.ts} +1 -1
- package/lib/src/_service-principal.js +69 -0
- package/lib/src/{storage.d.ts → _storage.d.ts} +4 -6
- package/lib/src/_storage.js +94 -0
- package/lib/src/_types.d.ts +40 -0
- package/lib/src/_types.js +2 -0
- package/lib/src/client.d.ts +30 -0
- package/lib/src/client.js +223 -0
- package/lib/src/config.d.ts +36 -0
- package/lib/src/config.js +15 -0
- package/lib/src/profile.d.ts +11 -0
- package/lib/src/profile.js +21 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +34 -10
- package/src/{databricks-cli.ts → _databricks-cli.ts} +20 -109
- package/src/_errors.ts +11 -0
- package/src/{lifecycle.ts → _lifecycle.ts} +24 -48
- package/src/_logging.ts +2 -2
- package/src/{personal-access-token.ts → _personal-access-token.ts} +1 -1
- package/src/_profile-config.ts +545 -0
- package/src/{service-principal.ts → _service-principal.ts} +2 -2
- package/src/_storage.ts +109 -0
- package/src/_types.ts +45 -0
- package/src/client.ts +291 -0
- package/src/config.ts +44 -0
- package/src/profile.ts +33 -0
- package/lib/exports.d.ts +0 -2
- package/lib/exports.js +0 -3
- package/lib/src/_profile-core.d.ts +0 -28
- package/lib/src/_profile-core.js +0 -216
- package/lib/src/_profile.d.ts +0 -15
- package/lib/src/_profile.js +0 -236
- package/lib/src/databricks-auth.d.ts +0 -11
- package/lib/src/databricks-auth.js +0 -314
- package/lib/src/databricks-cli.js +0 -239
- package/lib/src/errors.d.ts +0 -7
- package/lib/src/errors.js +0 -14
- package/lib/src/generated/databricks-cli-assets.json +0 -33
- package/lib/src/http-client.d.ts +0 -23
- package/lib/src/http-client.js +0 -116
- package/lib/src/lifecycle.js +0 -229
- package/lib/src/node-storage.d.ts +0 -20
- package/lib/src/node-storage.js +0 -207
- package/lib/src/personal-access-token.js +0 -30
- package/lib/src/service-principal.js +0 -69
- package/lib/src/storage.js +0 -98
- package/lib/src/types.d.ts +0 -157
- package/lib/src/types.js +0 -67
- package/src/_profile-core.ts +0 -258
- package/src/_profile.ts +0 -319
- package/src/databricks-auth.ts +0 -416
- package/src/errors.ts +0 -16
- package/src/generated/databricks-cli-assets.json +0 -33
- package/src/http-client.ts +0 -147
- package/src/node-storage.ts +0 -230
- package/src/storage.ts +0 -104
- package/src/types.ts +0 -188
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { isAbsolute, resolve } from "node:path";
|
|
5
|
+
import { AuthType, TargetKind } from "@dbx-tools/shared-auth/config";
|
|
6
|
+
import * as environmentUtils from "@dbx-tools/shared-core/environment-utils";
|
|
7
|
+
import * as object from "@dbx-tools/shared-core/object";
|
|
8
|
+
import * as stringUtils from "@dbx-tools/shared-core/string-utils";
|
|
9
|
+
import { trimToUndefined } from "@dbx-tools/shared-core/string-utils";
|
|
10
|
+
import { parse as parseIni } from "ini";
|
|
11
|
+
import { AuthError } from "./_errors.js";
|
|
12
|
+
import { authLogger } from "./_logging.js";
|
|
13
|
+
import { DEFAULT_ACCESS_TOKEN_HEADER, DEFAULT_CLIENT_ID, DEFAULT_CONFIG_FILE, } from "./config.js";
|
|
14
|
+
const logger = authLogger("profile-selection");
|
|
15
|
+
const configCache = new Map();
|
|
16
|
+
export const SETTINGS_SECTION = "__settings__";
|
|
17
|
+
/** Resolve the selected Databricks configuration path. */
|
|
18
|
+
export function resolveConfigFile(explicit, environment = process.env) {
|
|
19
|
+
const selected = trimToUndefined(explicit) ??
|
|
20
|
+
trimToUndefined(environment.DATABRICKS_CONFIG_FILE) ??
|
|
21
|
+
DEFAULT_CONFIG_FILE;
|
|
22
|
+
const expanded = selected === "~"
|
|
23
|
+
? homedir()
|
|
24
|
+
: selected.startsWith("~/")
|
|
25
|
+
? resolve(homedir(), selected.slice(2))
|
|
26
|
+
: selected;
|
|
27
|
+
return isAbsolute(expanded) ? expanded : resolve(expanded);
|
|
28
|
+
}
|
|
29
|
+
/** Load and cache the selected Databricks configuration. */
|
|
30
|
+
export function loadConfig(configFile, refresh = false, environment = process.env) {
|
|
31
|
+
const path = resolveConfigFile(configFile, environment);
|
|
32
|
+
if (refresh)
|
|
33
|
+
configCache.delete(path);
|
|
34
|
+
if (configCache.has(path)) {
|
|
35
|
+
const cached = configCache.get(path);
|
|
36
|
+
if (cached instanceof Error)
|
|
37
|
+
throw cached;
|
|
38
|
+
return cached;
|
|
39
|
+
}
|
|
40
|
+
if (!existsSync(path)) {
|
|
41
|
+
configCache.set(path, undefined);
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const config = parseDatabricksConfig(readFileSync(path, "utf8"));
|
|
46
|
+
configCache.set(path, config);
|
|
47
|
+
return config;
|
|
48
|
+
}
|
|
49
|
+
catch (cause) {
|
|
50
|
+
const error = cause instanceof Error ? cause : new AuthError("config", `Could not read ${path}`, { cause });
|
|
51
|
+
configCache.set(path, error);
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Invalidate cached configuration after an external write. */
|
|
56
|
+
export function invalidateConfigFile(configFile) {
|
|
57
|
+
configCache.delete(resolveConfigFile(configFile));
|
|
58
|
+
}
|
|
59
|
+
/** Parse Databricks INI text through the maintained `ini` package. */
|
|
60
|
+
export function parseDatabricksConfig(source) {
|
|
61
|
+
let parsed;
|
|
62
|
+
try {
|
|
63
|
+
parsed = parseIni(source);
|
|
64
|
+
}
|
|
65
|
+
catch (cause) {
|
|
66
|
+
throw new AuthError("config", "Databricks configuration is not valid INI", { cause });
|
|
67
|
+
}
|
|
68
|
+
const config = new Map();
|
|
69
|
+
for (const [name, value] of Object.entries(parsed)) {
|
|
70
|
+
if (!name.trim() || !object.isRecord(value)) {
|
|
71
|
+
throw new AuthError("config", "Databricks configuration values must belong to a profile");
|
|
72
|
+
}
|
|
73
|
+
const section = new Map();
|
|
74
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
75
|
+
if (entry === undefined || entry === null)
|
|
76
|
+
continue;
|
|
77
|
+
section.set(key.trim().toLowerCase(), String(entry).trim());
|
|
78
|
+
}
|
|
79
|
+
config.set(name.trim(), section);
|
|
80
|
+
}
|
|
81
|
+
return config;
|
|
82
|
+
}
|
|
83
|
+
export function loadRawProfile(config, name) {
|
|
84
|
+
const section = config?.get(name);
|
|
85
|
+
return {
|
|
86
|
+
host: section?.get("host"),
|
|
87
|
+
accountId: section?.get("account_id"),
|
|
88
|
+
workspaceId: section?.get("workspace_id"),
|
|
89
|
+
clientId: section?.get("client_id"),
|
|
90
|
+
clientSecret: section?.get("client_secret"),
|
|
91
|
+
accessToken: section?.get("token"),
|
|
92
|
+
groupId: section?.get("group_id"),
|
|
93
|
+
scopes: section?.get("scopes"),
|
|
94
|
+
authType: trimToUndefined(section?.get("auth_type"))?.toLowerCase(),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
export function resolveProfileName(requested, explicit, config, preferUserToMachine) {
|
|
98
|
+
let selected = requested;
|
|
99
|
+
let source = requested ? "requested" : undefined;
|
|
100
|
+
if (!selected) {
|
|
101
|
+
selected = trimToUndefined(config?.get(SETTINGS_SECTION)?.get("default_profile"));
|
|
102
|
+
if (selected)
|
|
103
|
+
source = "settings-default";
|
|
104
|
+
}
|
|
105
|
+
if (!selected && config?.has("DEFAULT")) {
|
|
106
|
+
selected = "DEFAULT";
|
|
107
|
+
source = "default-section";
|
|
108
|
+
}
|
|
109
|
+
if (!selected) {
|
|
110
|
+
const profiles = [...(config?.keys() ?? [])].filter((name) => name !== SETTINGS_SECTION);
|
|
111
|
+
if (profiles.length === 1) {
|
|
112
|
+
selected = profiles[0];
|
|
113
|
+
source = "sole-profile";
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!selected) {
|
|
117
|
+
selected = "DEFAULT";
|
|
118
|
+
source = "fallback";
|
|
119
|
+
}
|
|
120
|
+
if (selected === SETTINGS_SECTION) {
|
|
121
|
+
throw new AuthError("config", `${SETTINGS_SECTION} is reserved`);
|
|
122
|
+
}
|
|
123
|
+
if (explicit || !preferUserToMachine || !config) {
|
|
124
|
+
logger.debug("selected Databricks profile", {
|
|
125
|
+
profile: selected,
|
|
126
|
+
source,
|
|
127
|
+
explicit,
|
|
128
|
+
preferUserToMachine,
|
|
129
|
+
});
|
|
130
|
+
return selected;
|
|
131
|
+
}
|
|
132
|
+
const current = loadRawProfile(config, selected);
|
|
133
|
+
if (!isM2mProfile(current) || !current.host) {
|
|
134
|
+
logger.debug("selected Databricks profile", {
|
|
135
|
+
profile: selected,
|
|
136
|
+
source,
|
|
137
|
+
explicit,
|
|
138
|
+
preferUserToMachine,
|
|
139
|
+
});
|
|
140
|
+
return selected;
|
|
141
|
+
}
|
|
142
|
+
const matches = [...config.keys()].filter((name) => {
|
|
143
|
+
if (name === selected || name === SETTINGS_SECTION)
|
|
144
|
+
return false;
|
|
145
|
+
const candidate = loadRawProfile(config, name);
|
|
146
|
+
return candidate.authType === "databricks-cli" && sameTarget(current, candidate);
|
|
147
|
+
});
|
|
148
|
+
const preferred = matches.length === 1 ? matches[0] : selected;
|
|
149
|
+
logger.debug("selected Databricks profile", {
|
|
150
|
+
profile: preferred,
|
|
151
|
+
source: preferred === selected ? source : "matching-cli-profile",
|
|
152
|
+
originalProfile: preferred === selected ? undefined : selected,
|
|
153
|
+
explicit,
|
|
154
|
+
preferUserToMachine,
|
|
155
|
+
matchingCliProfiles: matches.length,
|
|
156
|
+
});
|
|
157
|
+
return preferred;
|
|
158
|
+
}
|
|
159
|
+
/** Normalize Databricks hosts and require TLS outside loopback development. */
|
|
160
|
+
export function normalizeHost(value, profile = "DEFAULT") {
|
|
161
|
+
const selected = trimToUndefined(value);
|
|
162
|
+
if (!selected)
|
|
163
|
+
throw new AuthError("config", `Profile ${profile} has no host`);
|
|
164
|
+
const withScheme = /^https?:\/\//i.test(selected) ? selected : `https://${selected}`;
|
|
165
|
+
let url;
|
|
166
|
+
try {
|
|
167
|
+
url = new URL(withScheme);
|
|
168
|
+
}
|
|
169
|
+
catch (cause) {
|
|
170
|
+
throw new AuthError("config", `Profile ${profile} has an invalid host`, { cause });
|
|
171
|
+
}
|
|
172
|
+
if (url.protocol !== "https:" && url.hostname !== "localhost" && url.hostname !== "127.0.0.1") {
|
|
173
|
+
throw new AuthError("config", "Databricks host must use HTTPS");
|
|
174
|
+
}
|
|
175
|
+
return url.toString().replace(/\/$/, "");
|
|
176
|
+
}
|
|
177
|
+
export function resolveAuthType(authType, clientId, clientSecret, accessToken) {
|
|
178
|
+
switch (authType) {
|
|
179
|
+
case AuthType.DatabricksCli:
|
|
180
|
+
return AuthType.DatabricksCli;
|
|
181
|
+
case AuthType.OAuthM2M:
|
|
182
|
+
if (!clientId || !clientSecret) {
|
|
183
|
+
throw new AuthError("config", "oauth-m2m requires client_id and client_secret");
|
|
184
|
+
}
|
|
185
|
+
return AuthType.OAuthM2M;
|
|
186
|
+
case AuthType.PersonalAccessToken:
|
|
187
|
+
if (!accessToken)
|
|
188
|
+
throw new AuthError("config", "pat requires token");
|
|
189
|
+
return AuthType.PersonalAccessToken;
|
|
190
|
+
case AuthType.AppOnBehalfOf:
|
|
191
|
+
if (!accessToken) {
|
|
192
|
+
throw new AuthError("config", "app_obo requires the configured access token header");
|
|
193
|
+
}
|
|
194
|
+
return AuthType.AppOnBehalfOf;
|
|
195
|
+
case AuthType.AppServicePrincipal:
|
|
196
|
+
if (!clientId || !clientSecret) {
|
|
197
|
+
throw new AuthError("config", "app_sp requires client id and secret");
|
|
198
|
+
}
|
|
199
|
+
return AuthType.AppServicePrincipal;
|
|
200
|
+
case undefined:
|
|
201
|
+
if (clientId && clientSecret)
|
|
202
|
+
return AuthType.OAuthM2M;
|
|
203
|
+
if (clientSecret)
|
|
204
|
+
throw new AuthError("config", "oauth-m2m client_secret requires client_id");
|
|
205
|
+
return accessToken ? AuthType.PersonalAccessToken : AuthType.DatabricksCli;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/** Parse one external auth-type value into the canonical enum. */
|
|
209
|
+
export function parseAuthType(value) {
|
|
210
|
+
const selected = trimToUndefined(value)?.toLowerCase();
|
|
211
|
+
if (selected === undefined)
|
|
212
|
+
return undefined;
|
|
213
|
+
if (Object.values(AuthType).includes(selected))
|
|
214
|
+
return selected;
|
|
215
|
+
throw new AuthError("config", `Authentication type ${selected} is not supported`);
|
|
216
|
+
}
|
|
217
|
+
export function requestOboToken(headers, headerName = DEFAULT_ACCESS_TOKEN_HEADER) {
|
|
218
|
+
const entry = Object.entries(headers ?? {}).find(([name]) => name.toLowerCase() === headerName.toLowerCase());
|
|
219
|
+
const value = trimToUndefined(entry?.[1]);
|
|
220
|
+
if (!value)
|
|
221
|
+
return undefined;
|
|
222
|
+
if (headerName.toLowerCase() !== DEFAULT_ACCESS_TOKEN_HEADER)
|
|
223
|
+
return value;
|
|
224
|
+
const [scheme, ...parts] = value.split(/\s+/);
|
|
225
|
+
return scheme?.toLowerCase() === "bearer" ? trimToUndefined(parts.join(" ")) : undefined;
|
|
226
|
+
}
|
|
227
|
+
export function inferTarget(host, accountId) {
|
|
228
|
+
if (accountId && host) {
|
|
229
|
+
try {
|
|
230
|
+
if (new URL(normalizeHost(host)).hostname === "accounts.cloud.databricks.com") {
|
|
231
|
+
return TargetKind.Account;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
catch { }
|
|
235
|
+
}
|
|
236
|
+
return TargetKind.Workspace;
|
|
237
|
+
}
|
|
238
|
+
export function parseTarget(value) {
|
|
239
|
+
switch (value.trim().toLowerCase()) {
|
|
240
|
+
case TargetKind.Workspace:
|
|
241
|
+
return TargetKind.Workspace;
|
|
242
|
+
case TargetKind.Account:
|
|
243
|
+
return TargetKind.Account;
|
|
244
|
+
case TargetKind.Unified:
|
|
245
|
+
return TargetKind.Unified;
|
|
246
|
+
default:
|
|
247
|
+
throw new AuthError("config", "Target must be workspace, account, or unified");
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
export function missing(profile, field) {
|
|
251
|
+
throw new AuthError("config", `Profile ${profile} requires ${field}`);
|
|
252
|
+
}
|
|
253
|
+
function sameTarget(left, right) {
|
|
254
|
+
try {
|
|
255
|
+
if (normalizeHost(left.host) !== normalizeHost(right.host))
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
return ((!left.accountId || left.accountId === right.accountId) &&
|
|
262
|
+
(!left.workspaceId || left.workspaceId === right.workspaceId));
|
|
263
|
+
}
|
|
264
|
+
function isM2mProfile(profile) {
|
|
265
|
+
return (profile.authType === AuthType.OAuthM2M ||
|
|
266
|
+
(!profile.authType && Boolean(profile.clientId && profile.clientSecret)));
|
|
267
|
+
}
|
|
268
|
+
/** Enumerate secret-free profile metadata from cached configuration. */
|
|
269
|
+
export function listDatabricksProfiles(configFile, refresh = false, environment = process.env) {
|
|
270
|
+
const path = resolveConfigFile(configFile, environment);
|
|
271
|
+
const config = loadConfig(configFile, refresh, environment);
|
|
272
|
+
if (!config) {
|
|
273
|
+
logger.debug("listed Databricks profiles", { path, refresh, count: 0 });
|
|
274
|
+
return [];
|
|
275
|
+
}
|
|
276
|
+
const profiles = [...config.keys()]
|
|
277
|
+
.filter((name) => name !== SETTINGS_SECTION)
|
|
278
|
+
.map((name) => {
|
|
279
|
+
const profile = loadRawProfile(config, name);
|
|
280
|
+
const host = stringUtils.trimToUndefined(profile.host);
|
|
281
|
+
const accountId = stringUtils.trimToUndefined(profile.accountId);
|
|
282
|
+
const workspaceId = stringUtils.trimToUndefined(profile.workspaceId);
|
|
283
|
+
const authType = resolveAuthType(parseAuthType(profile.authType), profile.clientId, profile.clientSecret, profile.accessToken);
|
|
284
|
+
return {
|
|
285
|
+
name,
|
|
286
|
+
...(host ? { host } : {}),
|
|
287
|
+
...(accountId ? { accountId } : {}),
|
|
288
|
+
...(workspaceId ? { workspaceId } : {}),
|
|
289
|
+
target: inferTarget(host, accountId),
|
|
290
|
+
authType,
|
|
291
|
+
principal: authType === AuthType.OAuthM2M || authType === AuthType.AppServicePrincipal
|
|
292
|
+
? (stringUtils.trimToUndefined(profile.clientId) ?? name)
|
|
293
|
+
: name,
|
|
294
|
+
};
|
|
295
|
+
})
|
|
296
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
297
|
+
logger.debug("listed Databricks profiles", { path, refresh, count: profiles.length });
|
|
298
|
+
return profiles;
|
|
299
|
+
}
|
|
300
|
+
/** Resolve options, environment, request headers, and configuration into credentials. */
|
|
301
|
+
export function resolveDatabricksProfile(options, environment = process.env) {
|
|
302
|
+
const inApp = environmentUtils.isDatabricksAppEnv({ ...environment });
|
|
303
|
+
const environmentProfile = stringUtils.trimToUndefined(environment.DATABRICKS_CONFIG_PROFILE);
|
|
304
|
+
const explicitProfile = Boolean(stringUtils.trimToUndefined(options.profile) ?? environmentProfile);
|
|
305
|
+
const requestToken = requestOboToken(options.requestHeaders, options.accessTokenHeader);
|
|
306
|
+
const explicitAuthType = options.authType ??
|
|
307
|
+
(!inApp && !explicitProfile ? parseAuthType(environment.DATABRICKS_AUTH_TYPE) : undefined);
|
|
308
|
+
const appServicePrincipal = [
|
|
309
|
+
environment.DATABRICKS_HOST,
|
|
310
|
+
environment.DATABRICKS_CLIENT_ID,
|
|
311
|
+
environment.DATABRICKS_CLIENT_SECRET,
|
|
312
|
+
].every((value) => Boolean(stringUtils.trimToUndefined(value)));
|
|
313
|
+
const selectedAuthType = !inApp || explicitProfile || explicitAuthType
|
|
314
|
+
? explicitAuthType
|
|
315
|
+
: requestToken
|
|
316
|
+
? AuthType.AppOnBehalfOf
|
|
317
|
+
: appServicePrincipal
|
|
318
|
+
? AuthType.AppServicePrincipal
|
|
319
|
+
: undefined;
|
|
320
|
+
const appAuth = selectedAuthType === AuthType.AppOnBehalfOf ||
|
|
321
|
+
selectedAuthType === AuthType.AppServicePrincipal;
|
|
322
|
+
const ignoreAmbientCredentials = explicitProfile && !appAuth;
|
|
323
|
+
const configPath = resolveConfigFile(options.configFile, environment);
|
|
324
|
+
const config = loadConfig(options.configFile, false, environment);
|
|
325
|
+
const requestedName = stringUtils.trimToUndefined(options.profile) ?? environmentProfile;
|
|
326
|
+
const profileName = resolveProfileName(requestedName, explicitProfile, config, options.preferUserToMachine ?? true);
|
|
327
|
+
const ambientCredentials = [
|
|
328
|
+
options.accessToken,
|
|
329
|
+
options.clientId,
|
|
330
|
+
options.clientSecret,
|
|
331
|
+
environment.DATABRICKS_TOKEN,
|
|
332
|
+
environment.DATABRICKS_CLIENT_ID,
|
|
333
|
+
environment.DATABRICKS_CLIENT_SECRET,
|
|
334
|
+
].some((value) => Boolean(stringUtils.trimToUndefined(value)));
|
|
335
|
+
const selectedProfile = explicitProfile || (!ambientCredentials && config?.has(profileName)) ? profileName : undefined;
|
|
336
|
+
const configured = loadRawProfile(config, profileName);
|
|
337
|
+
const ambient = (name) => ignoreAmbientCredentials ? undefined : stringUtils.trimToUndefined(environment[name]);
|
|
338
|
+
const host = normalizeHost(options.host ?? ambient("DATABRICKS_HOST") ?? configured.host, profileName);
|
|
339
|
+
const accountId = stringUtils.trimToUndefined(options.accountId) ??
|
|
340
|
+
ambient("DATABRICKS_ACCOUNT_ID") ??
|
|
341
|
+
stringUtils.trimToUndefined(configured.accountId);
|
|
342
|
+
const workspaceId = stringUtils.trimToUndefined(options.workspaceId) ??
|
|
343
|
+
ambient("DATABRICKS_WORKSPACE_ID") ??
|
|
344
|
+
stringUtils.trimToUndefined(configured.workspaceId);
|
|
345
|
+
const clientIdValue = stringUtils.trimToUndefined(options.clientId) ??
|
|
346
|
+
ambient("DATABRICKS_CLIENT_ID") ??
|
|
347
|
+
stringUtils.trimToUndefined(configured.clientId);
|
|
348
|
+
const clientSecret = stringUtils.trimToUndefined(options.clientSecret) ??
|
|
349
|
+
ambient("DATABRICKS_CLIENT_SECRET") ??
|
|
350
|
+
stringUtils.trimToUndefined(configured.clientSecret);
|
|
351
|
+
const accessToken = selectedAuthType === AuthType.AppOnBehalfOf
|
|
352
|
+
? requestToken
|
|
353
|
+
: (stringUtils.trimToUndefined(options.accessToken) ??
|
|
354
|
+
ambient("DATABRICKS_TOKEN") ??
|
|
355
|
+
stringUtils.trimToUndefined(configured.accessToken));
|
|
356
|
+
const configuredAuthType = selectedAuthType ??
|
|
357
|
+
parseAuthType(ambient("DATABRICKS_AUTH_TYPE")) ??
|
|
358
|
+
parseAuthType(configured.authType);
|
|
359
|
+
const authType = resolveAuthType(configuredAuthType, clientIdValue, clientSecret, accessToken);
|
|
360
|
+
const clientId = authType === AuthType.DatabricksCli
|
|
361
|
+
? (clientIdValue ?? DEFAULT_CLIENT_ID)
|
|
362
|
+
: authType === AuthType.OAuthM2M || authType === AuthType.AppServicePrincipal
|
|
363
|
+
? (clientIdValue ?? missing(profileName, "client_id"))
|
|
364
|
+
: (clientIdValue ?? "");
|
|
365
|
+
const scopes = options.scopes?.length
|
|
366
|
+
? stringUtils.parseList(options.scopes)
|
|
367
|
+
: stringUtils.parseList(configured.scopes?.split(",") ?? ["all-apis"]);
|
|
368
|
+
const target = options.target ? parseTarget(options.target) : inferTarget(host, accountId);
|
|
369
|
+
const groupId = stringUtils.trimToUndefined(options.groupId) ??
|
|
370
|
+
ambient("DATABRICKS_GROUP_ID") ??
|
|
371
|
+
stringUtils.trimToUndefined(configured.groupId);
|
|
372
|
+
const principal = authType === AuthType.OAuthM2M || authType === AuthType.AppServicePrincipal
|
|
373
|
+
? clientId
|
|
374
|
+
: profileName;
|
|
375
|
+
const cacheKey = credentialCacheKey({
|
|
376
|
+
name: profileName,
|
|
377
|
+
host,
|
|
378
|
+
accountId,
|
|
379
|
+
workspaceId,
|
|
380
|
+
clientId,
|
|
381
|
+
groupId,
|
|
382
|
+
scopes,
|
|
383
|
+
authType,
|
|
384
|
+
accessToken,
|
|
385
|
+
});
|
|
386
|
+
logger.debug("resolved Databricks profile", {
|
|
387
|
+
profile: profileName,
|
|
388
|
+
host,
|
|
389
|
+
authType,
|
|
390
|
+
target,
|
|
391
|
+
inApp,
|
|
392
|
+
explicitProfile,
|
|
393
|
+
configuredAuthType: configuredAuthType ?? "automatic",
|
|
394
|
+
hasAccountId: Boolean(accountId),
|
|
395
|
+
hasWorkspaceId: Boolean(workspaceId),
|
|
396
|
+
hasGroupId: Boolean(groupId),
|
|
397
|
+
scopeCount: scopes.length,
|
|
398
|
+
configPath,
|
|
399
|
+
});
|
|
400
|
+
return {
|
|
401
|
+
name: profileName,
|
|
402
|
+
...(selectedProfile ? { selectedProfile } : {}),
|
|
403
|
+
host,
|
|
404
|
+
...(accountId ? { accountId } : {}),
|
|
405
|
+
...(workspaceId ? { workspaceId } : {}),
|
|
406
|
+
clientId,
|
|
407
|
+
...(groupId ? { groupId } : {}),
|
|
408
|
+
scopes,
|
|
409
|
+
target,
|
|
410
|
+
authType,
|
|
411
|
+
...(clientSecret ? { clientSecret } : {}),
|
|
412
|
+
...(accessToken ? { accessToken } : {}),
|
|
413
|
+
cacheKey,
|
|
414
|
+
principal,
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
/** Normalize OAuth scopes for machine credentials. */
|
|
418
|
+
export function machineScopes(scopes) {
|
|
419
|
+
return stringUtils.parseList(scopes.length ? scopes : ["all-apis"]).sort();
|
|
420
|
+
}
|
|
421
|
+
function credentialCacheKey(profile) {
|
|
422
|
+
if (profile.authType === AuthType.DatabricksCli)
|
|
423
|
+
return profile.name;
|
|
424
|
+
if (profile.authType === AuthType.PersonalAccessToken) {
|
|
425
|
+
const digest = createHash("sha256")
|
|
426
|
+
.update(profile.accessToken ?? "")
|
|
427
|
+
.digest("hex");
|
|
428
|
+
return `${profile.name}-pat-${digest}`;
|
|
429
|
+
}
|
|
430
|
+
if (profile.authType === AuthType.AppOnBehalfOf)
|
|
431
|
+
return `${profile.name}-app-obo`;
|
|
432
|
+
const identity = [
|
|
433
|
+
profile.host,
|
|
434
|
+
profile.accountId ?? "",
|
|
435
|
+
profile.workspaceId ?? "",
|
|
436
|
+
profile.clientId,
|
|
437
|
+
profile.groupId ?? "",
|
|
438
|
+
machineScopes(profile.scopes).join(" "),
|
|
439
|
+
].join("\0");
|
|
440
|
+
const digest = createHash("sha256").update(identity).digest("hex");
|
|
441
|
+
return `${profile.name}-${profile.authType === AuthType.AppServicePrincipal ? "app-sp" : "oauth-m2m"}-${digest}`;
|
|
442
|
+
}
|
|
443
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX3Byb2ZpbGUtY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL19wcm9maWxlLWNvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxVQUFVLEVBQUUsWUFBWSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ25ELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDbEMsT0FBTyxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFaEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUVyRSxPQUFPLEtBQUssZ0JBQWdCLE1BQU0sMENBQTBDLENBQUM7QUFDN0UsT0FBTyxLQUFLLE1BQU0sTUFBTSwrQkFBK0IsQ0FBQztBQUN4RCxPQUFPLEtBQUssV0FBVyxNQUFNLHFDQUFxQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUN0RSxPQUFPLEVBQUUsS0FBSyxJQUFJLFFBQVEsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUV4QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFM0MsT0FBTyxFQUVMLDJCQUEyQixFQUMzQixpQkFBaUIsRUFDakIsbUJBQW1CLEdBQ3BCLE1BQU0sYUFBYSxDQUFDO0FBRXJCLE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0FBQy9DLE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxFQUF5QyxDQUFDO0FBRXJFLE1BQU0sQ0FBQyxNQUFNLGdCQUFnQixHQUFHLGNBQWMsQ0FBQztBQWlCL0MsMERBQTBEO0FBQzFELE1BQU0sVUFBVSxpQkFBaUIsQ0FDL0IsUUFB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LENBQUM7UUFDdEQsTUFBTSxNQUFNLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQzthQUNoQyxNQUFNLENBQUMsT0FBTyxDQUFDLFdBQVcsSUFBSSxFQUFFLENBQUM7YUFDakMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2pCLE9BQU8sR0FBRyxPQUFPLENBQUMsSUFBSSxRQUFRLE1BQU0sRUFBRSxDQUFDO0lBQ3pDLENBQUM7SUFDRCxJQUFJLE9BQU8sQ0FBQyxRQUFRLEtBQUssUUFBUSxDQUFDLGFBQWE7UUFBRSxPQUFPLEdBQUcsT0FBTyxDQUFDLElBQUksVUFBVSxDQUFDO0lBQ2xGLE1BQU0sUUFBUSxHQUFHO1FBQ2YsT0FBTyxDQUFDLElBQUk7UUFDWixPQUFPLENBQUMsU0FBUyxJQUFJLEVBQUU7UUFDdkIsT0FBTyxDQUFDLFdBQVcsSUFBSSxFQUFFO1FBQ3pCLE9BQU8sQ0FBQyxRQUFRO1FBQ2hCLE9BQU8sQ0FBQyxPQUFPLElBQUksRUFBRTtRQUNyQixhQUFhLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7S0FDeEMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDYixNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNuRSxPQUFPLEdBQUcsT0FBTyxDQUFDLElBQUksSUFBSSxPQUFPLENBQUMsUUFBUSxLQUFLLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxXQUFXLElBQUksTUFBTSxFQUFFLENBQUM7QUFDbkgsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyZWF0ZUhhc2ggfSBmcm9tIFwibm9kZTpjcnlwdG9cIjtcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYyB9IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBob21lZGlyIH0gZnJvbSBcIm5vZGU6b3NcIjtcbmltcG9ydCB7IGlzQWJzb2x1dGUsIHJlc29sdmUgfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5cbmltcG9ydCB7IEF1dGhUeXBlLCBUYXJnZXRLaW5kIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWF1dGgvY29uZmlnXCI7XG5pbXBvcnQgdHlwZSB7IERhdGFicmlja3NQcm9maWxlU3VtbWFyeSB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1hdXRoL3Byb2ZpbGVcIjtcbmltcG9ydCAqIGFzIGVudmlyb25tZW50VXRpbHMgZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmUvZW52aXJvbm1lbnQtdXRpbHNcIjtcbmltcG9ydCAqIGFzIG9iamVjdCBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZS9vYmplY3RcIjtcbmltcG9ydCAqIGFzIHN0cmluZ1V0aWxzIGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlL3N0cmluZy11dGlsc1wiO1xuaW1wb3J0IHsgdHJpbVRvVW5kZWZpbmVkIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmUvc3RyaW5nLXV0aWxzXCI7XG5pbXBvcnQgeyBwYXJzZSBhcyBwYXJzZUluaSB9IGZyb20gXCJpbmlcIjtcblxuaW1wb3J0IHsgQXV0aEVycm9yIH0gZnJvbSBcIi4vX2Vycm9ycy50c1wiO1xuaW1wb3J0IHsgYXV0aExvZ2dlciB9IGZyb20gXCIuL19sb2dnaW5nLnRzXCI7XG5pbXBvcnQgdHlwZSB7IERhdGFicmlja3NQcm9maWxlIH0gZnJvbSBcIi4vX3R5cGVzLnRzXCI7XG5pbXBvcnQge1xuICB0eXBlIERhdGFicmlja3NBdXRoT3B0aW9ucyxcbiAgREVGQVVMVF9BQ0NFU1NfVE9LRU5fSEVBREVSLFxuICBERUZBVUxUX0NMSUVOVF9JRCxcbiAgREVGQVVMVF9DT05GSUdfRklMRSxcbn0gZnJvbSBcIi4vY29uZmlnLnRzXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGF1dGhMb2dnZXIoXCJwcm9maWxlLXNlbGVjdGlvblwiKTtcbmNvbnN0IGNvbmZpZ0NhY2hlID0gbmV3IE1hcDxzdHJpbmcsIEluaUNvbmZpZyB8IEVycm9yIHwgdW5kZWZpbmVkPigpO1xuXG5leHBvcnQgY29uc3QgU0VUVElOR1NfU0VDVElPTiA9IFwiX19zZXR0aW5nc19fXCI7XG5cbmV4cG9ydCB0eXBlIEVudmlyb25tZW50ID0gUmVhZG9ubHk8UmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPj47XG5leHBvcnQgdHlwZSBJbmlDb25maWcgPSBNYXA8c3RyaW5nLCBNYXA8c3RyaW5nLCBzdHJpbmc+PjtcblxuZXhwb3J0IGludGVyZmFjZSBSYXdQcm9maWxlIHtcbiAgaG9zdD86IHN0cmluZztcbiAgYWNjb3VudElkPzogc3RyaW5nO1xuICB3b3Jrc3BhY2VJZD86IHN0cmluZztcbiAgY2xpZW50SWQ/OiBzdHJpbmc7XG4gIGNsaWVudFNlY3JldD86IHN0cmluZztcbiAgYWNjZXNzVG9rZW4/OiBzdHJpbmc7XG4gIGdyb3VwSWQ/OiBzdHJpbmc7XG4gIHNjb3Blcz86IHN0cmluZztcbiAgYXV0aFR5cGU/OiBzdHJpbmc7XG59XG5cbi8qKiBSZXNvbHZlIHRoZSBzZWxlY3RlZCBEYXRhYnJpY2tzIGNvbmZpZ3VyYXRpb24gcGF0aC4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlQ29uZmlnRmlsZShcbiAgZXhwbGljaXQ/OiBzdHJpbmcsXG4gIGVudmlyb25tZW50OiBFbnZpcm9ubWVudCA9IHByb2Nlc3MuZW52LFxuKTogc3RyaW5nIHtcbiAgY29uc3Qgc2VsZWN0ZWQgPVxuICAgIHRyaW1Ub1VuZGVmaW5lZChleHBsaWNpdCkgPz9cbiAgICB0cmltVG9VbmRlZmluZWQoZW52aXJvbm1lbnQuREFUQUJSSUNLU19DT05GSUdfRklMRSkgPz9cbiAgICBERUZBVUxUX0NPTkZJR19GSUxFO1xuICBjb25zdCBleHBhbmRlZCA9XG4gICAgc2VsZWN0ZWQgPT09IFwiflwiXG4gICAgICA/IGhvbWVkaXIoKVxuICAgICAgOiBzZWxlY3RlZC5zdGFydHNXaXRoKFwifi9cIilcbiAgICAgICAgPyByZXNvbHZlKGhvbWVkaXIoKSwgc2VsZWN0ZWQuc2xpY2UoMikpXG4gICAgICAgIDogc2VsZWN0ZWQ7XG4gIHJldHVybiBpc0Fic29sdXRlKGV4cGFuZGVkKSA/IGV4cGFuZGVkIDogcmVzb2x2ZShleHBhbmRlZCk7XG59XG5cbi8qKiBMb2FkIGFuZCBjYWNoZSB0aGUgc2VsZWN0ZWQgRGF0YWJyaWNrcyBjb25maWd1cmF0aW9uLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxvYWRDb25maWcoXG4gIGNvbmZpZ0ZpbGU/OiBzdHJpbmcsXG4gIHJlZnJlc2ggPSBmYWxzZSxcbiAgZW52aXJvbm1lbnQ6IEVudmlyb25tZW50ID0gcHJvY2Vzcy5lbnYsXG4pOiBJbmlDb25maWcgfCB1bmRlZmluZWQge1xuICBjb25zdCBwYXRoID0gcmVzb2x2ZUNvbmZpZ0ZpbGUoY29uZmlnRmlsZSwgZW52aXJvbm1lbnQpO1xuICBpZiAocmVmcmVzaCkgY29uZmlnQ2FjaGUuZGVsZXRlKHBhdGgpO1xuICBpZiAoY29uZmlnQ2FjaGUuaGFzKHBhdGgpKSB7XG4gICAgY29uc3QgY2FjaGVkID0gY29uZmlnQ2FjaGUuZ2V0KHBhdGgpO1xuICAgIGlmIChjYWNoZWQgaW5zdGFuY2VvZiBFcnJvcikgdGhyb3cgY2FjaGVkO1xuICAgIHJldHVybiBjYWNoZWQ7XG4gIH1cbiAgaWYgKCFleGlzdHNTeW5jKHBhdGgpKSB7XG4gICAgY29uZmlnQ2FjaGUuc2V0KHBhdGgsIHVuZGVmaW5lZCk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICB0cnkge1xuICAgIGNvbnN0IGNvbmZpZyA9IHBhcnNlRGF0YWJyaWNrc0NvbmZpZyhyZWFkRmlsZVN5bmMocGF0aCwgXCJ1dGY4XCIpKTtcbiAgICBjb25maWdDYWNoZS5zZXQocGF0aCwgY29uZmlnKTtcbiAgICByZXR1cm4gY29uZmlnO1xuICB9IGNhdGNoIChjYXVzZSkge1xuICAgIGNvbnN0IGVycm9yID1cbiAgICAgIGNhdXNlIGluc3RhbmNlb2YgRXJyb3IgPyBjYXVzZSA6IG5ldyBBdXRoRXJyb3IoXCJjb25maWdcIiwgYENvdWxkIG5vdCByZWFkICR7cGF0aH1gLCB7IGNhdXNlIH0pO1xuICAgIGNvbmZpZ0NhY2hlLnNldChwYXRoLCBlcnJvcik7XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cbn1cblxuLyoqIEludmFsaWRhdGUgY2FjaGVkIGNvbmZpZ3VyYXRpb24gYWZ0ZXIgYW4gZXh0ZXJuYWwgd3JpdGUuICovXG5leHBvcnQgZnVuY3Rpb24gaW52YWxpZGF0ZUNvbmZpZ0ZpbGUoY29uZmlnRmlsZT86IHN0cmluZyk6IHZvaWQge1xuICBjb25maWdDYWNoZS5kZWxldGUocmVzb2x2ZUNvbmZpZ0ZpbGUoY29uZmlnRmlsZSkpO1xufVxuXG4vKiogUGFyc2UgRGF0YWJyaWNrcyBJTkkgdGV4dCB0aHJvdWdoIHRoZSBtYWludGFpbmVkIGBpbmlgIHBhY2thZ2UuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VEYXRhYnJpY2tzQ29uZmlnKHNvdXJjZTogc3RyaW5nKTogSW5pQ29uZmlnIHtcbiAgbGV0IHBhcnNlZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIHRyeSB7XG4gICAgcGFyc2VkID0gcGFyc2VJbmkoc291cmNlKSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICB0aHJvdyBuZXcgQXV0aEVycm9yKFwiY29uZmlnXCIsIFwiRGF0YWJyaWNrcyBjb25maWd1cmF0aW9uIGlzIG5vdCB2YWxpZCBJTklcIiwgeyBjYXVzZSB9KTtcbiAgfVxuICBjb25zdCBjb25maWc6IEluaUNvbmZpZyA9IG5ldyBNYXAoKTtcbiAgZm9yIChjb25zdCBbbmFtZSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHBhcnNlZCkpIHtcbiAgICBpZiAoIW5hbWUudHJpbSgpIHx8ICFvYmplY3QuaXNSZWNvcmQodmFsdWUpKSB7XG4gICAgICB0aHJvdyBuZXcgQXV0aEVycm9yKFwiY29uZmlnXCIsIFwiRGF0YWJyaWNrcyBjb25maWd1cmF0aW9uIHZhbHVlcyBtdXN0IGJlbG9uZyB0byBhIHByb2ZpbGVcIik7XG4gICAgfVxuICAgIGNvbnN0IHNlY3Rpb24gPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuICAgIGZvciAoY29uc3QgW2tleSwgZW50cnldIG9mIE9iamVjdC5lbnRyaWVzKHZhbHVlKSkge1xuICAgICAgaWYgKGVudHJ5ID09PSB1bmRlZmluZWQgfHwgZW50cnkgPT09IG51bGwpIGNvbnRpbnVlO1xuICAgICAgc2VjdGlvbi5zZXQoa2V5LnRyaW0oKS50b0xvd2VyQ2FzZSgpLCBTdHJpbmcoZW50cnkpLnRyaW0oKSk7XG4gICAgfVxuICAgIGNvbmZpZy5zZXQobmFtZS50cmltKCksIHNlY3Rpb24pO1xuICB9XG4gIHJldHVybiBjb25maWc7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsb2FkUmF3UHJvZmlsZShjb25maWc6IEluaUNvbmZpZyB8IHVuZGVmaW5lZCwgbmFtZTogc3RyaW5nKTogUmF3UHJvZmlsZSB7XG4gIGNvbnN0IHNlY3Rpb24gPSBjb25maWc/LmdldChuYW1lKTtcbiAgcmV0dXJuIHtcbiAgICBob3N0OiBzZWN0aW9uPy5nZXQoXCJob3N0XCIpLFxuICAgIGFjY291bnRJZDogc2VjdGlvbj8uZ2V0KFwiYWNjb3VudF9pZFwiKSxcbiAgICB3b3Jrc3BhY2VJZDogc2VjdGlvbj8uZ2V0KFwid29ya3NwYWNlX2lkXCIpLFxuICAgIGNsaWVudElkOiBzZWN0aW9uPy5nZXQoXCJjbGllbnRfaWRcIiksXG4gICAgY2xpZW50U2VjcmV0OiBzZWN0aW9uPy5nZXQoXCJjbGllbnRfc2VjcmV0XCIpLFxuICAgIGFjY2Vzc1Rva2VuOiBzZWN0aW9uPy5nZXQoXCJ0b2tlblwiKSxcbiAgICBncm91cElkOiBzZWN0aW9uPy5nZXQoXCJncm91cF9pZFwiKSxcbiAgICBzY29wZXM6IHNlY3Rpb24/LmdldChcInNjb3Blc1wiKSxcbiAgICBhdXRoVHlwZTogdHJpbVRvVW5kZWZpbmVkKHNlY3Rpb24/LmdldChcImF1dGhfdHlwZVwiKSk/LnRvTG93ZXJDYXNlKCksXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlUHJvZmlsZU5hbWUoXG4gIHJlcXVlc3RlZDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICBleHBsaWNpdDogYm9vbGVhbixcbiAgY29uZmlnOiBJbmlDb25maWcgfCB1bmRlZmluZWQsXG4gIHByZWZlclVzZXJUb01hY2hpbmU6IGJvb2xlYW4sXG4pOiBzdHJpbmcge1xuICBsZXQgc2VsZWN0ZWQgPSByZXF1ZXN0ZWQ7XG4gIGxldCBzb3VyY2UgPSByZXF1ZXN0ZWQgPyBcInJlcXVlc3RlZFwiIDogdW5kZWZpbmVkO1xuICBpZiAoIXNlbGVjdGVkKSB7XG4gICAgc2VsZWN0ZWQgPSB0cmltVG9VbmRlZmluZWQoY29uZmlnPy5nZXQoU0VUVElOR1NfU0VDVElPTik/LmdldChcImRlZmF1bHRfcHJvZmlsZVwiKSk7XG4gICAgaWYgKHNlbGVjdGVkKSBzb3VyY2UgPSBcInNldHRpbmdzLWRlZmF1bHRcIjtcbiAgfVxuICBpZiAoIXNlbGVjdGVkICYmIGNvbmZpZz8uaGFzKFwiREVGQVVMVFwiKSkge1xuICAgIHNlbGVjdGVkID0gXCJERUZBVUxUXCI7XG4gICAgc291cmNlID0gXCJkZWZhdWx0LXNlY3Rpb25cIjtcbiAgfVxuICBpZiAoIXNlbGVjdGVkKSB7XG4gICAgY29uc3QgcHJvZmlsZXMgPSBbLi4uKGNvbmZpZz8ua2V5cygpID8/IFtdKV0uZmlsdGVyKChuYW1lKSA9PiBuYW1lICE9PSBTRVRUSU5HU19TRUNUSU9OKTtcbiAgICBpZiAocHJvZmlsZXMubGVuZ3RoID09PSAxKSB7XG4gICAgICBzZWxlY3RlZCA9IHByb2ZpbGVzWzBdO1xuICAgICAgc291cmNlID0gXCJzb2xlLXByb2ZpbGVcIjtcbiAgICB9XG4gIH1cbiAgaWYgKCFzZWxlY3RlZCkge1xuICAgIHNlbGVjdGVkID0gXCJERUZBVUxUXCI7XG4gICAgc291cmNlID0gXCJmYWxsYmFja1wiO1xuICB9XG4gIGlmIChzZWxlY3RlZCA9PT0gU0VUVElOR1NfU0VDVElPTikge1xuICAgIHRocm93IG5ldyBBdXRoRXJyb3IoXCJjb25maWdcIiwgYCR7U0VUVElOR1NfU0VDVElPTn0gaXMgcmVzZXJ2ZWRgKTtcbiAgfVxuICBpZiAoZXhwbGljaXQgfHwgIXByZWZlclVzZXJUb01hY2hpbmUgfHwgIWNvbmZpZykge1xuICAgIGxvZ2dlci5kZWJ1ZyhcInNlbGVjdGVkIERhdGFicmlja3MgcHJvZmlsZVwiLCB7XG4gICAgICBwcm9maWxlOiBzZWxlY3RlZCxcbiAgICAgIHNvdXJjZSxcbiAgICAgIGV4cGxpY2l0LFxuICAgICAgcHJlZmVyVXNlclRvTWFjaGluZSxcbiAgICB9KTtcbiAgICByZXR1cm4gc2VsZWN0ZWQ7XG4gIH1cbiAgY29uc3QgY3VycmVudCA9IGxvYWRSYXdQcm9maWxlKGNvbmZpZywgc2VsZWN0ZWQpO1xuICBpZiAoIWlzTTJtUHJvZmlsZShjdXJyZW50KSB8fCAhY3VycmVudC5ob3N0KSB7XG4gICAgbG9nZ2VyLmRlYnVnKFwic2VsZWN0ZWQgRGF0YWJyaWNrcyBwcm9maWxlXCIsIHtcbiAgICAgIHByb2ZpbGU6IHNlbGVjdGVkLFxuICAgICAgc291cmNlLFxuICAgICAgZXhwbGljaXQsXG4gICAgICBwcmVmZXJVc2VyVG9NYWNoaW5lLFxuICAgIH0pO1xuICAgIHJldHVybiBzZWxlY3RlZDtcbiAgfVxuICBjb25zdCBtYXRjaGVzID0gWy4uLmNvbmZpZy5rZXlzKCldLmZpbHRlcigobmFtZSkgPT4ge1xuICAgIGlmIChuYW1lID09PSBzZWxlY3RlZCB8fCBuYW1lID09PSBTRVRUSU5HU19TRUNUSU9OKSByZXR1cm4gZmFsc2U7XG4gICAgY29uc3QgY2FuZGlkYXRlID0gbG9hZFJhd1Byb2ZpbGUoY29uZmlnLCBuYW1lKTtcbiAgICByZXR1cm4gY2FuZGlkYXRlLmF1dGhUeXBlID09PSBcImRhdGFicmlja3MtY2xpXCIgJiYgc2FtZVRhcmdldChjdXJyZW50LCBjYW5kaWRhdGUpO1xuICB9KTtcbiAgY29uc3QgcHJlZmVycmVkID0gbWF0Y2hlcy5sZW5ndGggPT09IDEgPyBtYXRjaGVzWzBdISA6IHNlbGVjdGVkO1xuICBsb2dnZXIuZGVidWcoXCJzZWxlY3RlZCBEYXRhYnJpY2tzIHByb2ZpbGVcIiwge1xuICAgIHByb2ZpbGU6IHByZWZlcnJlZCxcbiAgICBzb3VyY2U6IHByZWZlcnJlZCA9PT0gc2VsZWN0ZWQgPyBzb3VyY2UgOiBcIm1hdGNoaW5nLWNsaS1wcm9maWxlXCIsXG4gICAgb3JpZ2luYWxQcm9maWxlOiBwcmVmZXJyZWQgPT09IHNlbGVjdGVkID8gdW5kZWZpbmVkIDogc2VsZWN0ZWQsXG4gICAgZXhwbGljaXQsXG4gICAgcHJlZmVyVXNlclRvTWFjaGluZSxcbiAgICBtYXRjaGluZ0NsaVByb2ZpbGVzOiBtYXRjaGVzLmxlbmd0aCxcbiAgfSk7XG4gIHJldHVybiBwcmVmZXJyZWQ7XG59XG5cbi8qKiBOb3JtYWxpemUgRGF0YWJyaWNrcyBob3N0cyBhbmQgcmVxdWlyZSBUTFMgb3V0c2lkZSBsb29wYmFjayBkZXZlbG9wbWVudC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVIb3N0KHZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWQsIHByb2ZpbGUgPSBcIkRFRkFVTFRcIik6IHN0cmluZyB7XG4gIGNvbnN0IHNlbGVjdGVkID0gdHJpbVRvVW5kZWZpbmVkKHZhbHVlKTtcbiAgaWYgKCFzZWxlY3RlZCkgdGhyb3cgbmV3IEF1dGhFcnJvcihcImNvbmZpZ1wiLCBgUHJvZmlsZSAke3Byb2ZpbGV9IGhhcyBubyBob3N0YCk7XG4gIGNvbnN0IHdpdGhTY2hlbWUgPSAvXmh0dHBzPzpcXC9cXC8vaS50ZXN0KHNlbGVjdGVkKSA/IHNlbGVjdGVkIDogYGh0dHBzOi8vJHtzZWxlY3RlZH1gO1xuICBsZXQgdXJsOiBVUkw7XG4gIHRyeSB7XG4gICAgdXJsID0gbmV3IFVSTCh3aXRoU2NoZW1lKTtcbiAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICB0aHJvdyBuZXcgQXV0aEVycm9yKFwiY29uZmlnXCIsIGBQcm9maWxlICR7cHJvZmlsZX0gaGFzIGFuIGludmFsaWQgaG9zdGAsIHsgY2F1c2UgfSk7XG4gIH1cbiAgaWYgKHVybC5wcm90b2NvbCAhPT0gXCJodHRwczpcIiAmJiB1cmwuaG9zdG5hbWUgIT09IFwibG9jYWxob3N0XCIgJiYgdXJsLmhvc3RuYW1lICE9PSBcIjEyNy4wLjAuMVwiKSB7XG4gICAgdGhyb3cgbmV3IEF1dGhFcnJvcihcImNvbmZpZ1wiLCBcIkRhdGFicmlja3MgaG9zdCBtdXN0IHVzZSBIVFRQU1wiKTtcbiAgfVxuICByZXR1cm4gdXJsLnRvU3RyaW5nKCkucmVwbGFjZSgvXFwvJC8sIFwiXCIpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUF1dGhUeXBlKFxuICBhdXRoVHlwZTogQXV0aFR5cGUgfCB1bmRlZmluZWQsXG4gIGNsaWVudElkOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIGNsaWVudFNlY3JldDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICBhY2Nlc3NUb2tlbjogc3RyaW5nIHwgdW5kZWZpbmVkLFxuKTogQXV0aFR5cGUge1xuICBzd2l0Y2ggKGF1dGhUeXBlKSB7XG4gICAgY2FzZSBBdXRoVHlwZS5EYXRhYnJpY2tzQ2xpOlxuICAgICAgcmV0dXJuIEF1dGhUeXBlLkRhdGFicmlja3NDbGk7XG4gICAgY2FzZSBBdXRoVHlwZS5PQXV0aE0yTTpcbiAgICAgIGlmICghY2xpZW50SWQgfHwgIWNsaWVudFNlY3JldCkge1xuICAgICAgICB0aHJvdyBuZXcgQXV0aEVycm9yKFwiY29uZmlnXCIsIFwib2F1dGgtbTJtIHJlcXVpcmVzIGNsaWVudF9pZCBhbmQgY2xpZW50X3NlY3JldFwiKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBBdXRoVHlwZS5PQXV0aE0yTTtcbiAgICBjYXNlIEF1dGhUeXBlLlBlcnNvbmFsQWNjZXNzVG9rZW46XG4gICAgICBpZiAoIWFjY2Vzc1Rva2VuKSB0aHJvdyBuZXcgQXV0aEVycm9yKFwiY29uZmlnXCIsIFwicGF0IHJlcXVpcmVzIHRva2VuXCIpO1xuICAgICAgcmV0dXJuIEF1dGhUeXBlLlBlcnNvbmFsQWNjZXNzVG9rZW47XG4gICAgY2FzZSBBdXRoVHlwZS5BcHBPbkJlaGFsZk9mOlxuICAgICAgaWYgKCFhY2Nlc3NUb2tlbikge1xuICAgICAgICB0aHJvdyBuZXcgQXV0aEVycm9yKFwiY29uZmlnXCIsIFwiYXBwX29ibyByZXF1aXJlcyB0aGUgY29uZmlndXJlZCBhY2Nlc3MgdG9rZW4gaGVhZGVyXCIpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIEF1dGhUeXBlLkFwcE9uQmVoYWxmT2Y7XG4gICAgY2FzZSBBdXRoVHlwZS5BcHBTZXJ2aWNlUHJpbmNpcGFsOlxuICAgICAgaWYgKCFjbGllbnRJZCB8fCAhY2xpZW50U2VjcmV0KSB7XG4gICAgICAgIHRocm93IG5ldyBBdXRoRXJyb3IoXCJjb25maWdcIiwgXCJhcHBfc3AgcmVxdWlyZXMgY2xpZW50IGlkIGFuZCBzZWNyZXRcIik7XG4gICAgICB9XG4gICAgICByZXR1cm4gQXV0aFR5cGUuQXBwU2VydmljZVByaW5jaXBhbDtcbiAgICBjYXNlIHVuZGVmaW5lZDpcbiAgICAgIGlmIChjbGllbnRJZCAmJiBjbGllbnRTZWNyZXQpIHJldHVybiBBdXRoVHlwZS5PQXV0aE0yTTtcbiAgICAgIGlmIChjbGllbnRTZWNyZXQpIHRocm93IG5ldyBBdXRoRXJyb3IoXCJjb25maWdcIiwgXCJvYXV0aC1tMm0gY2xpZW50X3NlY3JldCByZXF1aXJlcyBjbGllbnRfaWRcIik7XG4gICAgICByZXR1cm4gYWNjZXNzVG9rZW4gPyBBdXRoVHlwZS5QZXJzb25hbEFjY2Vzc1Rva2VuIDogQXV0aFR5cGUuRGF0YWJyaWNrc0NsaTtcbiAgfVxufVxuXG4vKiogUGFyc2Ugb25lIGV4dGVybmFsIGF1dGgtdHlwZSB2YWx1ZSBpbnRvIHRoZSBjYW5vbmljYWwgZW51bS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUF1dGhUeXBlKHZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBBdXRoVHlwZSB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHNlbGVjdGVkID0gdHJpbVRvVW5kZWZpbmVkKHZhbHVlKT8udG9Mb3dlckNhc2UoKTtcbiAgaWYgKHNlbGVjdGVkID09PSB1bmRlZmluZWQpIHJldHVybiB1bmRlZmluZWQ7XG4gIGlmIChPYmplY3QudmFsdWVzKEF1dGhUeXBlKS5pbmNsdWRlcyhzZWxlY3RlZCBhcyBBdXRoVHlwZSkpIHJldHVybiBzZWxlY3RlZCBhcyBBdXRoVHlwZTtcbiAgdGhyb3cgbmV3IEF1dGhFcnJvcihcImNvbmZpZ1wiLCBgQXV0aGVudGljYXRpb24gdHlwZSAke3NlbGVjdGVkfSBpcyBub3Qgc3VwcG9ydGVkYCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZXF1ZXN0T2JvVG9rZW4oXG4gIGhlYWRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LFxuICBoZWFkZXJOYW1lID0gREVGQVVMVF9BQ0NFU1NfVE9LRU5fSEVBREVSLFxuKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgZW50cnkgPSBPYmplY3QuZW50cmllcyhoZWFkZXJzID8/IHt9KS5maW5kKFxuICAgIChbbmFtZV0pID0+IG5hbWUudG9Mb3dlckNhc2UoKSA9PT0gaGVhZGVyTmFtZS50b0xvd2VyQ2FzZSgpLFxuICApO1xuICBjb25zdCB2YWx1ZSA9IHRyaW1Ub1VuZGVmaW5lZChlbnRyeT8uWzFdKTtcbiAgaWYgKCF2YWx1ZSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgaWYgKGhlYWRlck5hbWUudG9Mb3dlckNhc2UoKSAhPT0gREVGQVVMVF9BQ0NFU1NfVE9LRU5fSEVBREVSKSByZXR1cm4gdmFsdWU7XG4gIGNvbnN0IFtzY2hlbWUsIC4uLnBhcnRzXSA9IHZhbHVlLnNwbGl0KC9cXHMrLyk7XG4gIHJldHVybiBzY2hlbWU/LnRvTG93ZXJDYXNlKCkgPT09IFwiYmVhcmVyXCIgPyB0cmltVG9VbmRlZmluZWQocGFydHMuam9pbihcIiBcIikpIDogdW5kZWZpbmVkO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaW5mZXJUYXJnZXQoaG9zdDogc3RyaW5nIHwgdW5kZWZpbmVkLCBhY2NvdW50SWQ6IHN0cmluZyB8IHVuZGVmaW5lZCk6IFRhcmdldEtpbmQge1xuICBpZiAoYWNjb3VudElkICYmIGhvc3QpIHtcbiAgICB0cnkge1xuICAgICAgaWYgKG5ldyBVUkwobm9ybWFsaXplSG9zdChob3N0KSkuaG9zdG5hbWUgPT09IFwiYWNjb3VudHMuY2xvdWQuZGF0YWJyaWNrcy5jb21cIikge1xuICAgICAgICByZXR1cm4gVGFyZ2V0S2luZC5BY2NvdW50O1xuICAgICAgfVxuICAgIH0gY2F0Y2gge31cbiAgfVxuICByZXR1cm4gVGFyZ2V0S2luZC5Xb3Jrc3BhY2U7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZVRhcmdldCh2YWx1ZTogc3RyaW5nKTogVGFyZ2V0S2luZCB7XG4gIHN3aXRjaCAodmFsdWUudHJpbSgpLnRvTG93ZXJDYXNlKCkpIHtcbiAgICBjYXNlIFRhcmdldEtpbmQuV29ya3NwYWNlOlxuICAgICAgcmV0dXJuIFRhcmdldEtpbmQuV29ya3NwYWNlO1xuICAgIGNhc2UgVGFyZ2V0S2luZC5BY2NvdW50OlxuICAgICAgcmV0dXJuIFRhcmdldEtpbmQuQWNjb3VudDtcbiAgICBjYXNlIFRhcmdldEtpbmQuVW5pZmllZDpcbiAgICAgIHJldHVybiBUYXJnZXRLaW5kLlVuaWZpZWQ7XG4gICAgZGVmYXVsdDpcbiAgICAgIHRocm93IG5ldyBBdXRoRXJyb3IoXCJjb25maWdcIiwgXCJUYXJnZXQgbXVzdCBiZSB3b3Jrc3BhY2UsIGFjY291bnQsIG9yIHVuaWZpZWRcIik7XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG1pc3NpbmcocHJvZmlsZTogc3RyaW5nLCBmaWVsZDogc3RyaW5nKTogbmV2ZXIge1xuICB0aHJvdyBuZXcgQXV0aEVycm9yKFwiY29uZmlnXCIsIGBQcm9maWxlICR7cHJvZmlsZX0gcmVxdWlyZXMgJHtmaWVsZH1gKTtcbn1cblxuZnVuY3Rpb24gc2FtZVRhcmdldChsZWZ0OiBSYXdQcm9maWxlLCByaWdodDogUmF3UHJvZmlsZSk6IGJvb2xlYW4ge1xuICB0cnkge1xuICAgIGlmIChub3JtYWxpemVIb3N0KGxlZnQuaG9zdCkgIT09IG5vcm1hbGl6ZUhvc3QocmlnaHQuaG9zdCkpIHJldHVybiBmYWxzZTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiAoXG4gICAgKCFsZWZ0LmFjY291bnRJZCB8fCBsZWZ0LmFjY291bnRJZCA9PT0gcmlnaHQuYWNjb3VudElkKSAmJlxuICAgICghbGVmdC53b3Jrc3BhY2VJZCB8fCBsZWZ0LndvcmtzcGFjZUlkID09PSByaWdodC53b3Jrc3BhY2VJZClcbiAgKTtcbn1cblxuZnVuY3Rpb24gaXNNMm1Qcm9maWxlKHByb2ZpbGU6IFJhd1Byb2ZpbGUpOiBib29sZWFuIHtcbiAgcmV0dXJuIChcbiAgICBwcm9maWxlLmF1dGhUeXBlID09PSBBdXRoVHlwZS5PQXV0aE0yTSB8fFxuICAgICghcHJvZmlsZS5hdXRoVHlwZSAmJiBCb29sZWFuKHByb2ZpbGUuY2xpZW50SWQgJiYgcHJvZmlsZS5jbGllbnRTZWNyZXQpKVxuICApO1xufVxuXG4vKiogRW51bWVyYXRlIHNlY3JldC1mcmVlIHByb2ZpbGUgbWV0YWRhdGEgZnJvbSBjYWNoZWQgY29uZmlndXJhdGlvbi4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsaXN0RGF0YWJyaWNrc1Byb2ZpbGVzKFxuICBjb25maWdGaWxlPzogc3RyaW5nLFxuICByZWZyZXNoID0gZmFsc2UsXG4gIGVudmlyb25tZW50OiBFbnZpcm9ubWVudCA9IHByb2Nlc3MuZW52LFxuKTogRGF0YWJyaWNrc1Byb2ZpbGVTdW1tYXJ5W10ge1xuICBjb25zdCBwYXRoID0gcmVzb2x2ZUNvbmZpZ0ZpbGUoY29uZmlnRmlsZSwgZW52aXJvbm1lbnQpO1xuICBjb25zdCBjb25maWcgPSBsb2FkQ29uZmlnKGNvbmZpZ0ZpbGUsIHJlZnJlc2gsIGVudmlyb25tZW50KTtcbiAgaWYgKCFjb25maWcpIHtcbiAgICBsb2dnZXIuZGVidWcoXCJsaXN0ZWQgRGF0YWJyaWNrcyBwcm9maWxlc1wiLCB7IHBhdGgsIHJlZnJlc2gsIGNvdW50OiAwIH0pO1xuICAgIHJldHVybiBbXTtcbiAgfVxuICBjb25zdCBwcm9maWxlcyA9IFsuLi5jb25maWcua2V5cygpXVxuICAgIC5maWx0ZXIoKG5hbWUpID0+IG5hbWUgIT09IFNFVFRJTkdTX1NFQ1RJT04pXG4gICAgLm1hcCgobmFtZSkgPT4ge1xuICAgICAgY29uc3QgcHJvZmlsZSA9IGxvYWRSYXdQcm9maWxlKGNvbmZpZywgbmFtZSk7XG4gICAgICBjb25zdCBob3N0ID0gc3RyaW5nVXRpbHMudHJpbVRvVW5kZWZpbmVkKHByb2ZpbGUuaG9zdCk7XG4gICAgICBjb25zdCBhY2NvdW50SWQgPSBzdHJpbmdVdGlscy50cmltVG9VbmRlZmluZWQocHJvZmlsZS5hY2NvdW50SWQpO1xuICAgICAgY29uc3Qgd29ya3NwYWNlSWQgPSBzdHJpbmdVdGlscy50cmltVG9VbmRlZmluZWQocHJvZmlsZS53b3Jrc3BhY2VJZCk7XG4gICAgICBjb25zdCBhdXRoVHlwZSA9IHJlc29sdmVBdXRoVHlwZShcbiAgICAgICAgcGFyc2VBdXRoVHlwZShwcm9maWxlLmF1dGhUeXBlKSxcbiAgICAgICAgcHJvZmlsZS5jbGllbnRJZCxcbiAgICAgICAgcHJvZmlsZS5jbGllbnRTZWNyZXQsXG4gICAgICAgIHByb2ZpbGUuYWNjZXNzVG9rZW4sXG4gICAgICApO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbmFtZSxcbiAgICAgICAgLi4uKGhvc3QgPyB7IGhvc3QgfSA6IHt9KSxcbiAgICAgICAgLi4uKGFjY291bnRJZCA/IHsgYWNjb3VudElkIH0gOiB7fSksXG4gICAgICAgIC4uLih3b3Jrc3BhY2VJZCA/IHsgd29ya3NwYWNlSWQgfSA6IHt9KSxcbiAgICAgICAgdGFyZ2V0OiBpbmZlclRhcmdldChob3N0LCBhY2NvdW50SWQpLFxuICAgICAgICBhdXRoVHlwZSxcbiAgICAgICAgcHJpbmNpcGFsOlxuICAgICAgICAgIGF1dGhUeXBlID09PSBBdXRoVHlwZS5PQXV0aE0yTSB8fCBhdXRoVHlwZSA9PT0gQXV0aFR5cGUuQXBwU2VydmljZVByaW5jaXBhbFxuICAgICAgICAgICAgPyAoc3RyaW5nVXRpbHMudHJpbVRvVW5kZWZpbmVkKHByb2ZpbGUuY2xpZW50SWQpID8/IG5hbWUpXG4gICAgICAgICAgICA6IG5hbWUsXG4gICAgICB9O1xuICAgIH0pXG4gICAgLnNvcnQoKGxlZnQsIHJpZ2h0KSA9PiBsZWZ0Lm5hbWUubG9jYWxlQ29tcGFyZShyaWdodC5uYW1lKSk7XG4gIGxvZ2dlci5kZWJ1ZyhcImxpc3RlZCBEYXRhYnJpY2tzIHByb2ZpbGVzXCIsIHsgcGF0aCwgcmVmcmVzaCwgY291bnQ6IHByb2ZpbGVzLmxlbmd0aCB9KTtcbiAgcmV0dXJuIHByb2ZpbGVzO1xufVxuXG4vKiogUmVzb2x2ZSBvcHRpb25zLCBlbnZpcm9ubWVudCwgcmVxdWVzdCBoZWFkZXJzLCBhbmQgY29uZmlndXJhdGlvbiBpbnRvIGNyZWRlbnRpYWxzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVEYXRhYnJpY2tzUHJvZmlsZShcbiAgb3B0aW9uczogRGF0YWJyaWNrc0F1dGhPcHRpb25zLFxuICBlbnZpcm9ubWVudDogRW52aXJvbm1lbnQgPSBwcm9jZXNzLmVudixcbik6IERhdGFicmlja3NQcm9maWxlIHtcbiAgY29uc3QgaW5BcHAgPSBlbnZpcm9ubWVudFV0aWxzLmlzRGF0YWJyaWNrc0FwcEVudih7IC4uLmVudmlyb25tZW50IH0pO1xuICBjb25zdCBlbnZpcm9ubWVudFByb2ZpbGUgPSBzdHJpbmdVdGlscy50cmltVG9VbmRlZmluZWQoZW52aXJvbm1lbnQuREFUQUJSSUNLU19DT05GSUdfUFJPRklMRSk7XG4gIGNvbnN0IGV4cGxpY2l0UHJvZmlsZSA9IEJvb2xlYW4oXG4gICAgc3RyaW5nVXRpbHMudHJpbVRvVW5kZWZpbmVkKG9wdGlvbnMucHJvZmlsZSkgPz8gZW52aXJvbm1lbnRQcm9maWxlLFxuICApO1xuICBjb25zdCByZXF1ZXN0VG9rZW4gPSByZXF1ZXN0T2JvVG9rZW4ob3B0aW9ucy5yZXF1ZXN0SGVhZGVycywgb3B0aW9ucy5hY2Nlc3NUb2tlbkhlYWRlcik7XG4gIGNvbnN0IGV4cGxpY2l0QXV0aFR5cGUgPVxuICAgIG9wdGlvbnMuYXV0aFR5cGUgPz9cbiAgICAoIWluQXBwICYmICFleHBsaWNpdFByb2ZpbGUgPyBwYXJzZUF1dGhUeXBlKGVudmlyb25tZW50LkRBVEFCUklDS1NfQVVUSF9UWVBFKSA6IHVuZGVmaW5lZCk7XG4gIGNvbnN0IGFwcFNlcnZpY2VQcmluY2lwYWwgPSBbXG4gICAgZW52aXJvbm1lbnQuREFUQUJSSUNLU19IT1NULFxuICAgIGVudmlyb25tZW50LkRBVEFCUklDS1NfQ0xJRU5UX0lELFxuICAgIGVudmlyb25tZW50LkRBVEFCUklDS1NfQ0xJRU5UX1NFQ1JFVCxcbiAgXS5ldmVyeSgodmFsdWUpID0+IEJvb2xlYW4oc3RyaW5nVXRpbHMudHJpbVRvVW5kZWZpbmVkKHZhbHVlKSkpO1xuICBjb25zdCBzZWxlY3RlZEF1dGhUeXBlID1cbiAgICAhaW5BcHAgfHwgZXhwbGljaXRQcm9maWxlIHx8IGV4cGxpY2l0QXV0aFR5cGVcbiAgICAgID8gZXhwbGljaXRBdXRoVHlwZVxuICAgICAgOiByZXF1ZXN0VG9rZW5cbiAgICAgICAgPyBBdXRoVHlwZS5BcHBPbkJlaGFsZk9mXG4gICAgICAgIDogYXBwU2VydmljZVByaW5jaXBhbFxuICAgICAgICAgID8gQXV0aFR5cGUuQXBwU2VydmljZVByaW5jaXBhbFxuICAgICAgICAgIDogdW5kZWZpbmVkO1xuICBjb25zdCBhcHBBdXRoID1cbiAgICBzZWxlY3RlZEF1dGhUeXBlID09PSBBdXRoVHlwZS5BcHBPbkJlaGFsZk9mIHx8XG4gICAgc2VsZWN0ZWRBdXRoVHlwZSA9PT0gQXV0aFR5cGUuQXBwU2VydmljZVByaW5jaXBhbDtcbiAgY29uc3QgaWdub3JlQW1iaWVudENyZWRlbnRpYWxzID0gZXhwbGljaXRQcm9maWxlICYmICFhcHBBdXRoO1xuICBjb25zdCBjb25maWdQYXRoID0gcmVzb2x2ZUNvbmZpZ0ZpbGUob3B0aW9ucy5jb25maWdGaWxlLCBlbnZpcm9ubWVudCk7XG4gIGNvbnN0IGNvbmZpZyA9IGxvYWRDb25maWcob3B0aW9ucy5jb25maWdGaWxlLCBmYWxzZSwgZW52aXJvbm1lbnQpO1xuICBjb25zdCByZXF1ZXN0ZWROYW1lID0gc3RyaW5nVXRpbHMudHJpbVRvVW5kZWZpbmVkKG9wdGlvbnMucHJvZmlsZSkgPz8gZW52aXJvbm1lbnRQcm9maWxlO1xuICBjb25zdCBwcm9maWxlTmFtZSA9IHJlc29sdmVQcm9maWxlTmFtZShcbiAgICByZXF1ZXN0ZWROYW1lLFxuICAgIGV4cGxpY2l0UHJvZmlsZSxcbiAgICBjb25maWcsXG4gICAgb3B0aW9ucy5wcmVmZXJVc2VyVG9NYWNoaW5lID8/IHRydWUsXG4gICk7XG4gIGNvbnN0IGFtYmllbnRDcmVkZW50aWFscyA9IFtcbiAgICBvcHRpb25zLmFjY2Vzc1Rva2VuLFxuICAgIG9wdGlvbnMuY2xpZW50SWQsXG4gICAgb3B0aW9ucy5jbGllbnRTZWNyZXQsXG4gICAgZW52aXJvbm1lbnQuREFUQUJSSUNLU19UT0tFTixcbiAgICBlbnZpcm9ubWVudC5EQVRBQlJJQ0tTX0NMSUVOVF9JRCxcbiAgICBlbnZpcm9ubWVudC5EQVRBQlJJQ0tTX0NMSUVOVF9TRUNSRVQsXG4gIF0uc29tZSgodmFsdWUpID0+IEJvb2xlYW4oc3RyaW5nVXRpbHMudHJpbVRvVW5kZWZpbmVkKHZhbHVlKSkpO1xuICBjb25zdCBzZWxlY3RlZFByb2ZpbGUgPVxuICAgIGV4cGxpY2l0UHJvZmlsZSB8fCAoIWFtYmllbnRDcmVkZW50aWFscyAmJiBjb25maWc/Lmhhcyhwcm9maWxlTmFtZSkpID8gcHJvZmlsZU5hbWUgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IGNvbmZpZ3VyZWQgPSBsb2FkUmF3UHJvZmlsZShjb25maWcsIHByb2ZpbGVOYW1lKTtcbiAgY29uc3QgYW1iaWVudCA9IChuYW1lOiBrZXlvZiBOb2RlSlMuUHJvY2Vzc0Vudik6IHN0cmluZyB8IHVuZGVmaW5lZCA9PlxuICAgIGlnbm9yZUFtYmllbnRDcmVkZW50aWFscyA/IHVuZGVmaW5lZCA6IHN0cmluZ1V0aWxzLnRyaW1Ub1VuZGVmaW5lZChlbnZpcm9ubWVudFtuYW1lXSk7XG4gIGNvbnN0IGhvc3QgPSBub3JtYWxpemVIb3N0KFxuICAgIG9wdGlvbnMuaG9zdCA/PyBhbWJpZW50KFwiREFUQUJSSUNLU19IT1NUXCIpID8/IGNvbmZpZ3VyZWQuaG9zdCxcbiAgICBwcm9maWxlTmFtZSxcbiAgKTtcbiAgY29uc3QgYWNjb3VudElkID1cbiAgICBzdHJpbmdVdGlscy50cmltVG9VbmRlZmluZWQob3B0aW9ucy5hY2NvdW50SWQpID8/XG4gICAgYW1iaWVudChcIkRBVEFCUklDS1NfQUNDT1VOVF9JRFwiKSA/P1xuICAgIHN0cmluZ1V0aWxzLnRyaW1Ub1VuZGVmaW5lZChjb25maWd1cmVkLmFjY291bnRJZCk7XG4gIGNvbnN0IHdvcmtzcGFjZUlkID1cbiAgICBzdHJpbmdVdGlscy50cmltVG9VbmRlZmluZWQob3B0aW9ucy53b3Jrc3BhY2VJZCkgPz9cbiAgICBhbWJpZW50KFwiREFUQUJSSUNLU19XT1JLU1BBQ0VfSURcIikgPz9cbiAgICBzdHJpbmdVdGlscy50cmltVG9VbmRlZmluZWQoY29uZmlndXJlZC53b3Jrc3BhY2VJZCk7XG4gIGNvbnN0IGNsaWVudElkVmFsdWUgPVxuICAgIHN0cmluZ1V0aWxzLnRyaW1Ub1VuZGVmaW5lZChvcHRpb25zLmNsaWVudElkKSA/P1xuICAgIGFtYmllbnQoXCJEQVRBQlJJQ0tTX0NMSUVOVF9JRFwiKSA/P1xuICAgIHN0cmluZ1V0aWxzLnRyaW1Ub1VuZGVmaW5lZChjb25maWd1cmVkLmNsaWVudElkKTtcbiAgY29uc3QgY2xpZW50U2VjcmV0ID1cbiAgICBzdHJpbmdVdGlscy50cmltVG9VbmRlZmluZWQob3B0aW9ucy5jbGllbnRTZWNyZXQpID8/XG4gICAgYW1iaWVudChcIkRBVEFCUklDS1NfQ0xJRU5UX1NFQ1JFVFwiKSA/P1xuICAgIHN0cmluZ1V0aWxzLnRyaW1Ub1VuZGVmaW5lZChjb25maWd1cmVkLmNsaWVudFNlY3JldCk7XG4gIGNvbnN0IGFjY2Vzc1Rva2VuID1cbiAgICBzZWxlY3RlZEF1dGhUeXBlID09PSBBdXRoVHlwZS5BcHBPbkJlaGFsZk9mXG4gICAgICA/IHJlcXVlc3RUb2tlblxuICAgICAgOiAoc3RyaW5nVXRpbHMudHJpbVRvVW5kZWZpbmVkKG9wdGlvbnMuYWNjZXNzVG9rZW4pID8/XG4gICAgICAgIGFtYmllbnQoXCJEQVRBQlJJQ0tTX1RPS0VOXCIpID8/XG4gICAgICAgIHN0cmluZ1V0aWxzLnRyaW1Ub1VuZGVmaW5lZChjb25maWd1cmVkLmFjY2Vzc1Rva2VuKSk7XG4gIGNvbnN0IGNvbmZpZ3VyZWRBdXRoVHlwZSA9XG4gICAgc2VsZWN0ZWRBdXRoVHlwZSA/P1xuICAgIHBhcnNlQXV0aFR5cGUoYW1iaWVudChcIkRBVEFCUklDS1NfQVVUSF9UWVBFXCIpKSA/P1xuICAgIHBhcnNlQXV0aFR5cGUoY29uZmlndXJlZC5hdXRoVHlwZSk7XG4gIGNvbnN0IGF1dGhUeXBlID0gcmVzb2x2ZUF1dGhUeXBlKGNvbmZpZ3VyZWRBdXRoVHlwZSwgY2xpZW50SWRWYWx1ZSwgY2xpZW50U2VjcmV0LCBhY2Nlc3NUb2tlbik7XG4gIGNvbnN0IGNsaWVudElkID1cbiAgICBhdXRoVHlwZSA9PT0gQXV0aFR5cGUuRGF0YWJyaWNrc0NsaVxuICAgICAgPyAoY2xpZW50SWRWYWx1ZSA/PyBERUZBVUxUX0NMSUVOVF9JRClcbiAgICAgIDogYXV0aFR5cGUgPT09IEF1dGhUeXBlLk9BdXRoTTJNIHx8IGF1dGhUeXBlID09PSBBdXRoVHlwZS5BcHBTZXJ2aWNlUHJpbmNpcGFsXG4gICAgICAgID8gKGNsaWVudElkVmFsdWUgPz8gbWlzc2luZyhwcm9maWxlTmFtZSwgXCJjbGllbnRfaWRcIikpXG4gICAgICAgIDogKGNsaWVudElkVmFsdWUgPz8gXCJcIik7XG4gIGNvbnN0IHNjb3BlcyA9IG9wdGlvbnMuc2NvcGVzPy5sZW5ndGhcbiAgICA/IHN0cmluZ1V0aWxzLnBhcnNlTGlzdChvcHRpb25zLnNjb3BlcylcbiAgICA6IHN0cmluZ1V0aWxzLnBhcnNlTGlzdChjb25maWd1cmVkLnNjb3Blcz8uc3BsaXQoXCIsXCIpID8/IFtcImFsbC1hcGlzXCJdKTtcbiAgY29uc3QgdGFyZ2V0ID0gb3B0aW9ucy50YXJnZXQgPyBwYXJzZVRhcmdldChvcHRpb25zLnRhcmdldCkgOiBpbmZlclRhcmdldChob3N0LCBhY2NvdW50SWQpO1xuICBjb25zdCBncm91cElkID1cbiAgICBzdHJpbmdVdGlscy50cmltVG9VbmRlZmluZWQob3B0aW9ucy5ncm91cElkKSA/P1xuICAgIGFtYmllbnQoXCJEQVRBQlJJQ0tTX0dST1VQX0lEXCIpID8/XG4gICAgc3RyaW5nVXRpbHMudHJpbVRvVW5kZWZpbmVkKGNvbmZpZ3VyZWQuZ3JvdXBJZCk7XG4gIGNvbnN0IHByaW5jaXBhbCA9XG4gICAgYXV0aFR5cGUgPT09IEF1dGhUeXBlLk9BdXRoTTJNIHx8IGF1dGhUeXBlID09PSBBdXRoVHlwZS5BcHBTZXJ2aWNlUHJpbmNpcGFsXG4gICAgICA/IGNsaWVudElkXG4gICAgICA6IHByb2ZpbGVOYW1lO1xuICBjb25zdCBjYWNoZUtleSA9IGNyZWRlbnRpYWxDYWNoZUtleSh7XG4gICAgbmFtZTogcHJvZmlsZU5hbWUsXG4gICAgaG9zdCxcbiAgICBhY2NvdW50SWQsXG4gICAgd29ya3NwYWNlSWQsXG4gICAgY2xpZW50SWQsXG4gICAgZ3JvdXBJZCxcbiAgICBzY29wZXMsXG4gICAgYXV0aFR5cGUsXG4gICAgYWNjZXNzVG9rZW4sXG4gIH0pO1xuICBsb2dnZXIuZGVidWcoXCJyZXNvbHZlZCBEYXRhYnJpY2tzIHByb2ZpbGVcIiwge1xuICAgIHByb2ZpbGU6IHByb2ZpbGVOYW1lLFxuICAgIGhvc3QsXG4gICAgYXV0aFR5cGUsXG4gICAgdGFyZ2V0LFxuICAgIGluQXBwLFxuICAgIGV4cGxpY2l0UHJvZmlsZSxcbiAgICBjb25maWd1cmVkQXV0aFR5cGU6IGNvbmZpZ3VyZWRBdXRoVHlwZSA/PyBcImF1dG9tYXRpY1wiLFxuICAgIGhhc0FjY291bnRJZDogQm9vbGVhbihhY2NvdW50SWQpLFxuICAgIGhhc1dvcmtzcGFjZUlkOiBCb29sZWFuKHdvcmtzcGFjZUlkKSxcbiAgICBoYXNHcm91cElkOiBCb29sZWFuKGdyb3VwSWQpLFxuICAgIHNjb3BlQ291bnQ6IHNjb3Blcy5sZW5ndGgsXG4gICAgY29uZmlnUGF0aCxcbiAgfSk7XG4gIHJldHVybiB7XG4gICAgbmFtZTogcHJvZmlsZU5hbWUsXG4gICAgLi4uKHNlbGVjdGVkUHJvZmlsZSA/IHsgc2VsZWN0ZWRQcm9maWxlIH0gOiB7fSksXG4gICAgaG9zdCxcbiAgICAuLi4oYWNjb3VudElkID8geyBhY2NvdW50SWQgfSA6IHt9KSxcbiAgICAuLi4od29ya3NwYWNlSWQgPyB7IHdvcmtzcGFjZUlkIH0gOiB7fSksXG4gICAgY2xpZW50SWQsXG4gICAgLi4uKGdyb3VwSWQgPyB7IGdyb3VwSWQgfSA6IHt9KSxcbiAgICBzY29wZXMsXG4gICAgdGFyZ2V0LFxuICAgIGF1dGhUeXBlLFxuICAgIC4uLihjbGllbnRTZWNyZXQgPyB7IGNsaWVudFNlY3JldCB9IDoge30pLFxuICAgIC4uLihhY2Nlc3NUb2tlbiA/IHsgYWNjZXNzVG9rZW4gfSA6IHt9KSxcbiAgICBjYWNoZUtleSxcbiAgICBwcmluY2lwYWwsXG4gIH07XG59XG5cbi8qKiBOb3JtYWxpemUgT0F1dGggc2NvcGVzIGZvciBtYWNoaW5lIGNyZWRlbnRpYWxzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1hY2hpbmVTY29wZXMoc2NvcGVzOiByZWFkb25seSBzdHJpbmdbXSk6IHN0cmluZ1tdIHtcbiAgcmV0dXJuIHN0cmluZ1V0aWxzLnBhcnNlTGlzdChzY29wZXMubGVuZ3RoID8gc2NvcGVzIDogW1wiYWxsLWFwaXNcIl0pLnNvcnQoKTtcbn1cblxuZnVuY3Rpb24gY3JlZGVudGlhbENhY2hlS2V5KFxuICBwcm9maWxlOiBQaWNrPFxuICAgIERhdGFicmlja3NQcm9maWxlLFxuICAgIHwgXCJuYW1lXCJcbiAgICB8IFwiaG9zdFwiXG4gICAgfCBcImFjY291bnRJZFwiXG4gICAgfCBcIndvcmtzcGFjZUlkXCJcbiAgICB8IFwiY2xpZW50SWRcIlxuICAgIHwgXCJncm91cElkXCJcbiAgICB8IFwic2NvcGVzXCJcbiAgICB8IFwiYXV0aFR5cGVcIlxuICAgIHwgXCJhY2Nlc3NUb2tlblwiXG4gID4sXG4pOiBzdHJpbmcge1xuICBpZiAocHJvZmlsZS5hdXRoVHlwZSA9PT0gQXV0aFR5cGUuRGF0YWJyaWNrc0NsaSkgcmV0dXJuIHByb2ZpbGUubmFtZTtcbiAgaWYgKHByb2ZpbGUuYXV0aFR5cGUgPT09IEF1dGhUeXBlLlBlcnNvbmFsQWNjZXNzVG9rZW4pIHtcbiAgICBjb25zdCBkaWdlc3QgPSBjcmVhdGVIYXNoKFwic2hhMjU2XCIpXG4gICAgICAudXBkYXRlKHByb2ZpbGUuYWNjZXNzVG9rZW4gPz8gXCJcIilcbiAgICAgIC5kaWdlc3QoXCJoZXhcIik7XG4gICAgcmV0dXJuIGAke3Byb2ZpbGUubmFtZX0tcGF0LSR7ZGlnZXN0fWA7XG4gIH1cbiAgaWYgKHByb2ZpbGUuYXV0aFR5cGUgPT09IEF1dGhUeXBlLkFwcE9uQmVoYWxmT2YpIHJldHVybiBgJHtwcm9maWxlLm5hbWV9LWFwcC1vYm9gO1xuICBjb25zdCBpZGVudGl0eSA9IFtcbiAgICBwcm9maWxlLmhvc3QsXG4gICAgcHJvZmlsZS5hY2NvdW50SWQgPz8gXCJcIixcbiAgICBwcm9maWxlLndvcmtzcGFjZUlkID8/IFwiXCIsXG4gICAgcHJvZmlsZS5jbGllbnRJZCxcbiAgICBwcm9maWxlLmdyb3VwSWQgPz8gXCJcIixcbiAgICBtYWNoaW5lU2NvcGVzKHByb2ZpbGUuc2NvcGVzKS5qb2luKFwiIFwiKSxcbiAgXS5qb2luKFwiXFwwXCIpO1xuICBjb25zdCBkaWdlc3QgPSBjcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShpZGVudGl0eSkuZGlnZXN0KFwiaGV4XCIpO1xuICByZXR1cm4gYCR7cHJvZmlsZS5uYW1lfS0ke3Byb2ZpbGUuYXV0aFR5cGUgPT09IEF1dGhUeXBlLkFwcFNlcnZpY2VQcmluY2lwYWwgPyBcImFwcC1zcFwiIDogXCJvYXV0aC1tMm1cIn0tJHtkaWdlc3R9YDtcbn1cbiJdfQ==
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Token, TokenProvider } from "./
|
|
1
|
+
import type { Token, TokenProvider } from "./_types.ts";
|
|
2
2
|
/** Client-credentials inputs and transport options for Databricks OAuth. */
|
|
3
3
|
export interface DatabricksServicePrincipalConfig {
|
|
4
4
|
tokenEndpoint: string;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as oauth from "oauth4webapi";
|
|
2
|
+
import { AuthError } from "./_errors.js";
|
|
3
|
+
import { authLogger, failureMetadata, tokenMetadata } from "./_logging.js";
|
|
4
|
+
const logger = authLogger("service-principal");
|
|
5
|
+
/** Databricks service-principal provider backed by client credentials. */
|
|
6
|
+
export class DatabricksServicePrincipalProvider {
|
|
7
|
+
config;
|
|
8
|
+
authorizationServer;
|
|
9
|
+
client;
|
|
10
|
+
requestOptions;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.config = config;
|
|
13
|
+
this.authorizationServer = {
|
|
14
|
+
issuer: new URL(config.tokenEndpoint).origin,
|
|
15
|
+
token_endpoint: config.tokenEndpoint,
|
|
16
|
+
};
|
|
17
|
+
this.client = { client_id: config.clientId };
|
|
18
|
+
this.requestOptions = {
|
|
19
|
+
...(config.fetch ? { [oauth.customFetch]: config.fetch } : {}),
|
|
20
|
+
...(config.allowInsecureRequests ? { [oauth.allowInsecureRequests]: true } : {}),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
authenticate() {
|
|
24
|
+
return this.acquire();
|
|
25
|
+
}
|
|
26
|
+
login() {
|
|
27
|
+
return this.acquire();
|
|
28
|
+
}
|
|
29
|
+
refresh() {
|
|
30
|
+
return this.acquire();
|
|
31
|
+
}
|
|
32
|
+
canAuthenticateSilently() {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
async acquire() {
|
|
36
|
+
logger.debug("requesting service-principal token", {
|
|
37
|
+
tokenOrigin: new URL(this.config.tokenEndpoint).origin,
|
|
38
|
+
scopeCount: this.config.scopes.length,
|
|
39
|
+
hasGroupId: Boolean(this.config.groupId),
|
|
40
|
+
allowInsecureRequests: Boolean(this.config.allowInsecureRequests),
|
|
41
|
+
});
|
|
42
|
+
try {
|
|
43
|
+
const response = await oauth.clientCredentialsGrantRequest(this.authorizationServer, this.client, oauth.ClientSecretBasic(this.config.clientSecret), {
|
|
44
|
+
scope: [...new Set(this.config.scopes)].sort().join(" "),
|
|
45
|
+
...(this.config.groupId ? { assume_group: this.config.groupId } : {}),
|
|
46
|
+
}, this.requestOptions);
|
|
47
|
+
const value = await oauth.processClientCredentialsResponse(this.authorizationServer, this.client, response);
|
|
48
|
+
const token = {
|
|
49
|
+
accessToken: value.access_token,
|
|
50
|
+
tokenType: value.token_type.toLowerCase() === "bearer" ? "Bearer" : value.token_type,
|
|
51
|
+
...(value.expires_in !== undefined
|
|
52
|
+
? { expiry: new Date(Date.now() + value.expires_in * 1000).toISOString() }
|
|
53
|
+
: {}),
|
|
54
|
+
scopes: value.scope?.split(/\s+/).filter(Boolean) ?? [...this.config.scopes],
|
|
55
|
+
};
|
|
56
|
+
logger.debug("received service-principal token", { token: tokenMetadata(token) });
|
|
57
|
+
return token;
|
|
58
|
+
}
|
|
59
|
+
catch (cause) {
|
|
60
|
+
logger.debug("service-principal token request failed", {
|
|
61
|
+
error: failureMetadata(cause),
|
|
62
|
+
});
|
|
63
|
+
throw new AuthError("oauth", "Databricks service-principal authentication failed", {
|
|
64
|
+
cause,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX3NlcnZpY2UtcHJpbmNpcGFsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL19zZXJ2aWNlLXByaW5jaXBhbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssS0FBSyxNQUFNLGNBQWMsQ0FBQztBQUV0QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxVQUFVLEVBQUUsZUFBZSxFQUFFLGFBQWEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUczRSxNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsbUJBQW1CLENBQUMsQ0FBQztBQWEvQywwRUFBMEU7QUFDMUUsTUFBTSxPQUFPLGtDQUFrQztJQUtoQjtJQUpaLG1CQUFtQixDQUE0QjtJQUMvQyxNQUFNLENBQWU7SUFDckIsY0FBYyxDQUFvRDtJQUVuRixZQUE2QixNQUF3QztRQUF4QyxXQUFNLEdBQU4sTUFBTSxDQUFrQztRQUNuRSxJQUFJLENBQUMsbUJBQW1CLEdBQUc7WUFDekIsTUFBTSxFQUFFLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQyxNQUFNO1lBQzVDLGNBQWMsRUFBRSxNQUFNLENBQUMsYUFBYTtTQUNyQyxDQUFDO1FBQ0YsSUFBSSxDQUFDLE1BQU0sR0FBRyxFQUFFLFNBQVMsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDN0MsSUFBSSxDQUFDLGNBQWMsR0FBRztZQUNwQixHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxNQUFNLENBQUMsS0FBZ0MsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDekYsR0FBRyxDQUFDLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7U0FDakYsQ0FBQztJQUNKLENBQUM7SUFFRCxZQUFZO1FBQ1YsT0FBTyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDeEIsQ0FBQztJQUVELEtBQUs7UUFDSCxPQUFPLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUN4QixDQUFDO0lBRUQsT0FBTztRQUNMLE9BQU8sSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFFRCx1QkFBdUI7UUFDckIsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRU8sS0FBSyxDQUFDLE9BQU87UUFDbkIsTUFBTSxDQUFDLEtBQUssQ0FBQyxvQ0FBb0MsRUFBRTtZQUNqRCxXQUFXLEVBQUUsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQyxNQUFNO1lBQ3RELFVBQVUsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNO1lBQ3JDLFVBQVUsRUFBRSxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUM7WUFDeEMscUJBQXFCLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMscUJBQXFCLENBQUM7U0FDbEUsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDO1lBQ0gsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsNkJBQTZCLENBQ3hELElBQUksQ0FBQyxtQkFBbUIsRUFDeEIsSUFBSSxDQUFDLE1BQU0sRUFDWCxLQUFLLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsRUFDakQ7Z0JBQ0UsS0FBSyxFQUFFLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQztnQkFDeEQsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLFlBQVksRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7YUFDdEUsRUFDRCxJQUFJLENBQUMsY0FBYyxDQUNwQixDQUFDO1lBQ0YsTUFBTSxLQUFLLEdBQUcsTUFBTSxLQUFLLENBQUMsZ0NBQWdDLENBQ3hELElBQUksQ0FBQyxtQkFBbUIsRUFDeEIsSUFBSSxDQUFDLE1BQU0sRUFDWCxRQUFRLENBQ1QsQ0FBQztZQUNGLE1BQU0sS0FBSyxHQUFHO2dCQUNaLFdBQVcsRUFBRSxLQUFLLENBQUMsWUFBWTtnQkFDL0IsU0FBUyxFQUFFLEtBQUssQ0FBQyxVQUFVLENBQUMsV0FBVyxFQUFFLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxVQUFVO2dCQUNwRixHQUFHLENBQUMsS0FBSyxDQUFDLFVBQVUsS0FBSyxTQUFTO29CQUNoQyxDQUFDLENBQUMsRUFBRSxNQUFNLEVBQUUsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLEtBQUssQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUU7b0JBQzFFLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQ1AsTUFBTSxFQUFFLEtBQUssQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUM7YUFDN0UsQ0FBQztZQUNGLE1BQU0sQ0FBQyxLQUFLLENBQUMsa0NBQWtDLEVBQUUsRUFBRSxLQUFLLEVBQUUsYUFBYSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNsRixPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxDQUFDLEtBQUssQ0FBQyx3Q0FBd0MsRUFBRTtnQkFDckQsS0FBSyxFQUFFLGVBQWUsQ0FBQyxLQUFLLENBQUM7YUFDOUIsQ0FBQyxDQUFDO1lBQ0gsTUFBTSxJQUFJLFNBQVMsQ0FBQyxPQUFPLEVBQUUsb0RBQW9ELEVBQUU7Z0JBQ2pGLEtBQUs7YUFDTixDQUFDLENBQUM7UUFDTCxDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgb2F1dGggZnJvbSBcIm9hdXRoNHdlYmFwaVwiO1xuXG5pbXBvcnQgeyBBdXRoRXJyb3IgfSBmcm9tIFwiLi9fZXJyb3JzLnRzXCI7XG5pbXBvcnQgeyBhdXRoTG9nZ2VyLCBmYWlsdXJlTWV0YWRhdGEsIHRva2VuTWV0YWRhdGEgfSBmcm9tIFwiLi9fbG9nZ2luZy50c1wiO1xuaW1wb3J0IHR5cGUgeyBUb2tlbiwgVG9rZW5Qcm92aWRlciB9IGZyb20gXCIuL190eXBlcy50c1wiO1xuXG5jb25zdCBsb2dnZXIgPSBhdXRoTG9nZ2VyKFwic2VydmljZS1wcmluY2lwYWxcIik7XG5cbi8qKiBDbGllbnQtY3JlZGVudGlhbHMgaW5wdXRzIGFuZCB0cmFuc3BvcnQgb3B0aW9ucyBmb3IgRGF0YWJyaWNrcyBPQXV0aC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGF0YWJyaWNrc1NlcnZpY2VQcmluY2lwYWxDb25maWcge1xuICB0b2tlbkVuZHBvaW50OiBzdHJpbmc7XG4gIGNsaWVudElkOiBzdHJpbmc7XG4gIGNsaWVudFNlY3JldDogc3RyaW5nO1xuICBzY29wZXM6IHN0cmluZ1tdO1xuICBncm91cElkPzogc3RyaW5nO1xuICBmZXRjaD86IHR5cGVvZiBnbG9iYWxUaGlzLmZldGNoO1xuICBhbGxvd0luc2VjdXJlUmVxdWVzdHM/OiBib29sZWFuO1xufVxuXG4vKiogRGF0YWJyaWNrcyBzZXJ2aWNlLXByaW5jaXBhbCBwcm92aWRlciBiYWNrZWQgYnkgY2xpZW50IGNyZWRlbnRpYWxzLiAqL1xuZXhwb3J0IGNsYXNzIERhdGFicmlja3NTZXJ2aWNlUHJpbmNpcGFsUHJvdmlkZXIgaW1wbGVtZW50cyBUb2tlblByb3ZpZGVyIHtcbiAgcHJpdmF0ZSByZWFkb25seSBhdXRob3JpemF0aW9uU2VydmVyOiBvYXV0aC5BdXRob3JpemF0aW9uU2VydmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IGNsaWVudDogb2F1dGguQ2xpZW50O1xuICBwcml2YXRlIHJlYWRvbmx5IHJlcXVlc3RPcHRpb25zOiBvYXV0aC5IdHRwUmVxdWVzdE9wdGlvbnM8c3RyaW5nLCBVUkxTZWFyY2hQYXJhbXM+O1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgY29uZmlnOiBEYXRhYnJpY2tzU2VydmljZVByaW5jaXBhbENvbmZpZykge1xuICAgIHRoaXMuYXV0aG9yaXphdGlvblNlcnZlciA9IHtcbiAgICAgIGlzc3VlcjogbmV3IFVSTChjb25maWcudG9rZW5FbmRwb2ludCkub3JpZ2luLFxuICAgICAgdG9rZW5fZW5kcG9pbnQ6IGNvbmZpZy50b2tlbkVuZHBvaW50LFxuICAgIH07XG4gICAgdGhpcy5jbGllbnQgPSB7IGNsaWVudF9pZDogY29uZmlnLmNsaWVudElkIH07XG4gICAgdGhpcy5yZXF1ZXN0T3B0aW9ucyA9IHtcbiAgICAgIC4uLihjb25maWcuZmV0Y2ggPyB7IFtvYXV0aC5jdXN0b21GZXRjaF06IGNvbmZpZy5mZXRjaCBhcyB0eXBlb2YgZ2xvYmFsVGhpcy5mZXRjaCB9IDoge30pLFxuICAgICAgLi4uKGNvbmZpZy5hbGxvd0luc2VjdXJlUmVxdWVzdHMgPyB7IFtvYXV0aC5hbGxvd0luc2VjdXJlUmVxdWVzdHNdOiB0cnVlIH0gOiB7fSksXG4gICAgfTtcbiAgfVxuXG4gIGF1dGhlbnRpY2F0ZSgpOiBQcm9taXNlPFRva2VuPiB7XG4gICAgcmV0dXJuIHRoaXMuYWNxdWlyZSgpO1xuICB9XG5cbiAgbG9naW4oKTogUHJvbWlzZTxUb2tlbj4ge1xuICAgIHJldHVybiB0aGlzLmFjcXVpcmUoKTtcbiAgfVxuXG4gIHJlZnJlc2goKTogUHJvbWlzZTxUb2tlbj4ge1xuICAgIHJldHVybiB0aGlzLmFjcXVpcmUoKTtcbiAgfVxuXG4gIGNhbkF1dGhlbnRpY2F0ZVNpbGVudGx5KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBhY3F1aXJlKCk6IFByb21pc2U8VG9rZW4+IHtcbiAgICBsb2dnZXIuZGVidWcoXCJyZXF1ZXN0aW5nIHNlcnZpY2UtcHJpbmNpcGFsIHRva2VuXCIsIHtcbiAgICAgIHRva2VuT3JpZ2luOiBuZXcgVVJMKHRoaXMuY29uZmlnLnRva2VuRW5kcG9pbnQpLm9yaWdpbixcbiAgICAgIHNjb3BlQ291bnQ6IHRoaXMuY29uZmlnLnNjb3Blcy5sZW5ndGgsXG4gICAgICBoYXNHcm91cElkOiBCb29sZWFuKHRoaXMuY29uZmlnLmdyb3VwSWQpLFxuICAgICAgYWxsb3dJbnNlY3VyZVJlcXVlc3RzOiBCb29sZWFuKHRoaXMuY29uZmlnLmFsbG93SW5zZWN1cmVSZXF1ZXN0cyksXG4gICAgfSk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgb2F1dGguY2xpZW50Q3JlZGVudGlhbHNHcmFudFJlcXVlc3QoXG4gICAgICAgIHRoaXMuYXV0aG9yaXphdGlvblNlcnZlcixcbiAgICAgICAgdGhpcy5jbGllbnQsXG4gICAgICAgIG9hdXRoLkNsaWVudFNlY3JldEJhc2ljKHRoaXMuY29uZmlnLmNsaWVudFNlY3JldCksXG4gICAgICAgIHtcbiAgICAgICAgICBzY29wZTogWy4uLm5ldyBTZXQodGhpcy5jb25maWcuc2NvcGVzKV0uc29ydCgpLmpvaW4oXCIgXCIpLFxuICAgICAgICAgIC4uLih0aGlzLmNvbmZpZy5ncm91cElkID8geyBhc3N1bWVfZ3JvdXA6IHRoaXMuY29uZmlnLmdyb3VwSWQgfSA6IHt9KSxcbiAgICAgICAgfSxcbiAgICAgICAgdGhpcy5yZXF1ZXN0T3B0aW9ucyxcbiAgICAgICk7XG4gICAgICBjb25zdCB2YWx1ZSA9IGF3YWl0IG9hdXRoLnByb2Nlc3NDbGllbnRDcmVkZW50aWFsc1Jlc3BvbnNlKFxuICAgICAgICB0aGlzLmF1dGhvcml6YXRpb25TZXJ2ZXIsXG4gICAgICAgIHRoaXMuY2xpZW50LFxuICAgICAgICByZXNwb25zZSxcbiAgICAgICk7XG4gICAgICBjb25zdCB0b2tlbiA9IHtcbiAgICAgICAgYWNjZXNzVG9rZW46IHZhbHVlLmFjY2Vzc190b2tlbixcbiAgICAgICAgdG9rZW5UeXBlOiB2YWx1ZS50b2tlbl90eXBlLnRvTG93ZXJDYXNlKCkgPT09IFwiYmVhcmVyXCIgPyBcIkJlYXJlclwiIDogdmFsdWUudG9rZW5fdHlwZSxcbiAgICAgICAgLi4uKHZhbHVlLmV4cGlyZXNfaW4gIT09IHVuZGVmaW5lZFxuICAgICAgICAgID8geyBleHBpcnk6IG5ldyBEYXRlKERhdGUubm93KCkgKyB2YWx1ZS5leHBpcmVzX2luICogMTAwMCkudG9JU09TdHJpbmcoKSB9XG4gICAgICAgICAgOiB7fSksXG4gICAgICAgIHNjb3BlczogdmFsdWUuc2NvcGU/LnNwbGl0KC9cXHMrLykuZmlsdGVyKEJvb2xlYW4pID8/IFsuLi50aGlzLmNvbmZpZy5zY29wZXNdLFxuICAgICAgfTtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhcInJlY2VpdmVkIHNlcnZpY2UtcHJpbmNpcGFsIHRva2VuXCIsIHsgdG9rZW46IHRva2VuTWV0YWRhdGEodG9rZW4pIH0pO1xuICAgICAgcmV0dXJuIHRva2VuO1xuICAgIH0gY2F0Y2ggKGNhdXNlKSB7XG4gICAgICBsb2dnZXIuZGVidWcoXCJzZXJ2aWNlLXByaW5jaXBhbCB0b2tlbiByZXF1ZXN0IGZhaWxlZFwiLCB7XG4gICAgICAgIGVycm9yOiBmYWlsdXJlTWV0YWRhdGEoY2F1c2UpLFxuICAgICAgfSk7XG4gICAgICB0aHJvdyBuZXcgQXV0aEVycm9yKFwib2F1dGhcIiwgXCJEYXRhYnJpY2tzIHNlcnZpY2UtcHJpbmNpcGFsIGF1dGhlbnRpY2F0aW9uIGZhaWxlZFwiLCB7XG4gICAgICAgIGNhdXNlLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG59XG4iXX0=
|