mongodb 6.6.2-dev.20240529.sha.d3031a5 → 6.7.0-dev.20240530.sha.f56938f
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/lib/client-side-encryption/providers/azure.js +21 -6
- package/lib/client-side-encryption/providers/azure.js.map +1 -1
- package/lib/cmap/auth/mongo_credentials.js +24 -16
- package/lib/cmap/auth/mongo_credentials.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/automated_callback_workflow.js +78 -0
- package/lib/cmap/auth/mongodb_oidc/automated_callback_workflow.js.map +1 -0
- package/lib/cmap/auth/mongodb_oidc/azure_machine_workflow.js +74 -0
- package/lib/cmap/auth/mongodb_oidc/azure_machine_workflow.js.map +1 -0
- package/lib/cmap/auth/mongodb_oidc/callback_workflow.js +74 -135
- package/lib/cmap/auth/mongodb_oidc/callback_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/command_builders.js +45 -0
- package/lib/cmap/auth/mongodb_oidc/command_builders.js.map +1 -0
- package/lib/cmap/auth/mongodb_oidc/gcp_machine_workflow.js +46 -0
- package/lib/cmap/auth/mongodb_oidc/gcp_machine_workflow.js.map +1 -0
- package/lib/cmap/auth/mongodb_oidc/human_callback_workflow.js +122 -0
- package/lib/cmap/auth/mongodb_oidc/human_callback_workflow.js.map +1 -0
- package/lib/cmap/auth/mongodb_oidc/machine_workflow.js +107 -0
- package/lib/cmap/auth/mongodb_oidc/machine_workflow.js.map +1 -0
- package/lib/cmap/auth/mongodb_oidc/token_cache.js +52 -0
- package/lib/cmap/auth/mongodb_oidc/token_cache.js.map +1 -0
- package/lib/cmap/auth/mongodb_oidc/token_machine_workflow.js +34 -0
- package/lib/cmap/auth/mongodb_oidc/token_machine_workflow.js.map +1 -0
- package/lib/cmap/auth/mongodb_oidc.js +26 -24
- package/lib/cmap/auth/mongodb_oidc.js.map +1 -1
- package/lib/cmap/auth/providers.js +0 -1
- package/lib/cmap/auth/providers.js.map +1 -1
- package/lib/cmap/connect.js +4 -4
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +1 -1
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/connection_string.js +3 -0
- package/lib/connection_string.js.map +1 -1
- package/lib/error.js +57 -2
- package/lib/error.js.map +1 -1
- package/lib/index.js +5 -3
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +1 -1
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_client_auth_providers.js +34 -4
- package/lib/mongo_client_auth_providers.js.map +1 -1
- package/lib/utils.js +32 -2
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +105 -25
- package/package.json +5 -3
- package/src/client-side-encryption/providers/azure.ts +21 -10
- package/src/cmap/auth/mongo_credentials.ts +41 -34
- package/src/cmap/auth/mongodb_oidc/automated_callback_workflow.ts +82 -0
- package/src/cmap/auth/mongodb_oidc/azure_machine_workflow.ts +85 -0
- package/src/cmap/auth/mongodb_oidc/callback_workflow.ts +96 -204
- package/src/cmap/auth/mongodb_oidc/command_builders.ts +54 -0
- package/src/cmap/auth/mongodb_oidc/gcp_machine_workflow.ts +53 -0
- package/src/cmap/auth/mongodb_oidc/human_callback_workflow.ts +142 -0
- package/src/cmap/auth/mongodb_oidc/machine_workflow.ts +137 -0
- package/src/cmap/auth/mongodb_oidc/token_cache.ts +62 -0
- package/src/cmap/auth/mongodb_oidc/token_machine_workflow.ts +34 -0
- package/src/cmap/auth/mongodb_oidc.ts +79 -49
- package/src/cmap/auth/providers.ts +0 -1
- package/src/cmap/connect.ts +14 -4
- package/src/cmap/connection.ts +1 -0
- package/src/cmap/connection_pool.ts +2 -1
- package/src/connection_string.ts +3 -0
- package/src/error.ts +58 -1
- package/src/index.ts +8 -4
- package/src/mongo_client.ts +4 -1
- package/src/mongo_client_auth_providers.ts +44 -6
- package/src/utils.ts +33 -0
- package/lib/client-side-encryption/providers/utils.js +0 -35
- package/lib/client-side-encryption/providers/utils.js.map +0 -1
- package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js +0 -30
- package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js.map +0 -1
- package/lib/cmap/auth/mongodb_oidc/azure_service_workflow.js +0 -73
- package/lib/cmap/auth/mongodb_oidc/azure_service_workflow.js.map +0 -1
- package/lib/cmap/auth/mongodb_oidc/azure_token_cache.js +0 -49
- package/lib/cmap/auth/mongodb_oidc/azure_token_cache.js.map +0 -1
- package/lib/cmap/auth/mongodb_oidc/cache.js +0 -55
- package/lib/cmap/auth/mongodb_oidc/cache.js.map +0 -1
- package/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js +0 -90
- package/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js.map +0 -1
- package/lib/cmap/auth/mongodb_oidc/service_workflow.js +0 -43
- package/lib/cmap/auth/mongodb_oidc/service_workflow.js.map +0 -1
- package/lib/cmap/auth/mongodb_oidc/token_entry_cache.js +0 -62
- package/lib/cmap/auth/mongodb_oidc/token_entry_cache.js.map +0 -1
- package/src/client-side-encryption/providers/utils.ts +0 -37
- package/src/cmap/auth/mongodb_oidc/aws_service_workflow.ts +0 -29
- package/src/cmap/auth/mongodb_oidc/azure_service_workflow.ts +0 -86
- package/src/cmap/auth/mongodb_oidc/azure_token_cache.ts +0 -51
- package/src/cmap/auth/mongodb_oidc/cache.ts +0 -63
- package/src/cmap/auth/mongodb_oidc/callback_lock_cache.ts +0 -115
- package/src/cmap/auth/mongodb_oidc/service_workflow.ts +0 -49
- package/src/cmap/auth/mongodb_oidc/token_entry_cache.ts +0 -77
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { type Document } from '../../bson';
|
|
2
|
-
import {
|
|
2
|
+
import { MongoNetworkTimeoutError } from '../../error';
|
|
3
|
+
import { get } from '../../utils';
|
|
4
|
+
import { MongoCryptAzureKMSRequestError } from '../errors';
|
|
3
5
|
import { type KMSProviders } from './index';
|
|
4
|
-
import { get } from './utils';
|
|
5
6
|
|
|
6
7
|
const MINIMUM_TOKEN_REFRESH_IN_MILLISECONDS = 6000;
|
|
8
|
+
/** Base URL for getting Azure tokens. */
|
|
9
|
+
export const AZURE_BASE_URL = 'http://169.254.169.254/metadata/identity/oauth2/token?';
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* The access token that libmongocrypt expects for Azure kms.
|
|
@@ -113,6 +116,19 @@ export interface AzureKMSRequestOptions {
|
|
|
113
116
|
url?: URL | string;
|
|
114
117
|
}
|
|
115
118
|
|
|
119
|
+
/**
|
|
120
|
+
* @internal
|
|
121
|
+
* Get the Azure endpoint URL.
|
|
122
|
+
*/
|
|
123
|
+
export function addAzureParams(url: URL, resource: string, username?: string): URL {
|
|
124
|
+
url.searchParams.append('api-version', '2018-02-01');
|
|
125
|
+
url.searchParams.append('resource', resource);
|
|
126
|
+
if (username) {
|
|
127
|
+
url.searchParams.append('client_id', username);
|
|
128
|
+
}
|
|
129
|
+
return url;
|
|
130
|
+
}
|
|
131
|
+
|
|
116
132
|
/**
|
|
117
133
|
* @internal
|
|
118
134
|
*
|
|
@@ -123,13 +139,8 @@ export function prepareRequest(options: AzureKMSRequestOptions): {
|
|
|
123
139
|
headers: Document;
|
|
124
140
|
url: URL;
|
|
125
141
|
} {
|
|
126
|
-
const url = new URL(
|
|
127
|
-
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
url.searchParams.append('api-version', '2018-02-01');
|
|
131
|
-
url.searchParams.append('resource', 'https://vault.azure.net');
|
|
132
|
-
|
|
142
|
+
const url = new URL(options.url?.toString() ?? AZURE_BASE_URL);
|
|
143
|
+
addAzureParams(url, 'https://vault.azure.net');
|
|
133
144
|
const headers = { ...options.headers, 'Content-Type': 'application/json', Metadata: true };
|
|
134
145
|
return { headers, url };
|
|
135
146
|
}
|
|
@@ -152,7 +163,7 @@ export async function fetchAzureKMSToken(
|
|
|
152
163
|
const response = await get(url, { headers });
|
|
153
164
|
return await parseResponse(response);
|
|
154
165
|
} catch (error) {
|
|
155
|
-
if (error instanceof
|
|
166
|
+
if (error instanceof MongoNetworkTimeoutError) {
|
|
156
167
|
throw new MongoCryptAzureKMSRequestError(`[Azure KMS] ${error.message}`);
|
|
157
168
|
}
|
|
158
169
|
throw error;
|
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
import type { Document } from '../../bson';
|
|
4
4
|
import {
|
|
5
5
|
MongoAPIError,
|
|
6
|
-
MongoAzureError,
|
|
7
6
|
MongoInvalidArgumentError,
|
|
8
7
|
MongoMissingCredentialsError
|
|
9
8
|
} from '../../error';
|
|
10
9
|
import { GSSAPICanonicalizationValue } from './gssapi';
|
|
11
|
-
import type {
|
|
10
|
+
import type { OIDCCallbackFunction } from './mongodb_oidc';
|
|
12
11
|
import { AUTH_MECHS_AUTH_SRC_EXTERNAL, AuthMechanism } from './providers';
|
|
13
12
|
|
|
14
13
|
// https://github.com/mongodb/specifications/blob/master/source/auth/auth.rst
|
|
@@ -32,12 +31,17 @@ function getDefaultAuthMechanism(hello: Document | null): AuthMechanism {
|
|
|
32
31
|
return AuthMechanism.MONGODB_CR;
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
const
|
|
34
|
+
const ALLOWED_ENVIRONMENT_NAMES: AuthMechanismProperties['ENVIRONMENT'][] = [
|
|
35
|
+
'test',
|
|
36
|
+
'azure',
|
|
37
|
+
'gcp'
|
|
38
|
+
];
|
|
36
39
|
const ALLOWED_HOSTS_ERROR = 'Auth mechanism property ALLOWED_HOSTS must be an array of strings.';
|
|
37
40
|
|
|
38
41
|
/** @internal */
|
|
39
42
|
export const DEFAULT_ALLOWED_HOSTS = [
|
|
40
43
|
'*.mongodb.net',
|
|
44
|
+
'*.mongodb-qa.net',
|
|
41
45
|
'*.mongodb-dev.net',
|
|
42
46
|
'*.mongodbgov.net',
|
|
43
47
|
'localhost',
|
|
@@ -46,8 +50,8 @@ export const DEFAULT_ALLOWED_HOSTS = [
|
|
|
46
50
|
];
|
|
47
51
|
|
|
48
52
|
/** Error for when the token audience is missing in the environment. */
|
|
49
|
-
const
|
|
50
|
-
'
|
|
53
|
+
const TOKEN_RESOURCE_MISSING_ERROR =
|
|
54
|
+
'TOKEN_RESOURCE must be set in the auth mechanism properties when ENVIRONMENT is azure or gcp.';
|
|
51
55
|
|
|
52
56
|
/** @public */
|
|
53
57
|
export interface AuthMechanismProperties extends Document {
|
|
@@ -56,16 +60,16 @@ export interface AuthMechanismProperties extends Document {
|
|
|
56
60
|
SERVICE_REALM?: string;
|
|
57
61
|
CANONICALIZE_HOST_NAME?: GSSAPICanonicalizationValue;
|
|
58
62
|
AWS_SESSION_TOKEN?: string;
|
|
59
|
-
/**
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
|
|
65
|
-
/**
|
|
63
|
+
/** A user provided OIDC machine callback function. */
|
|
64
|
+
OIDC_CALLBACK?: OIDCCallbackFunction;
|
|
65
|
+
/** A user provided OIDC human interacted callback function. */
|
|
66
|
+
OIDC_HUMAN_CALLBACK?: OIDCCallbackFunction;
|
|
67
|
+
/** The OIDC environment. Note that 'test' is for internal use only. */
|
|
68
|
+
ENVIRONMENT?: 'test' | 'azure' | 'gcp';
|
|
69
|
+
/** Allowed hosts that OIDC auth can connect to. */
|
|
66
70
|
ALLOWED_HOSTS?: string[];
|
|
67
|
-
/**
|
|
68
|
-
|
|
71
|
+
/** The resource token for OIDC auth in Azure and GCP. */
|
|
72
|
+
TOKEN_RESOURCE?: string;
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
/** @public */
|
|
@@ -179,45 +183,48 @@ export class MongoCredentials {
|
|
|
179
183
|
}
|
|
180
184
|
|
|
181
185
|
if (this.mechanism === AuthMechanism.MONGODB_OIDC) {
|
|
182
|
-
if (
|
|
186
|
+
if (
|
|
187
|
+
this.username &&
|
|
188
|
+
this.mechanismProperties.ENVIRONMENT &&
|
|
189
|
+
this.mechanismProperties.ENVIRONMENT !== 'azure'
|
|
190
|
+
) {
|
|
183
191
|
throw new MongoInvalidArgumentError(
|
|
184
|
-
`username and
|
|
192
|
+
`username and ENVIRONMENT '${this.mechanismProperties.ENVIRONMENT}' may not be used together for mechanism '${this.mechanism}'.`
|
|
185
193
|
);
|
|
186
194
|
}
|
|
187
195
|
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
throw new MongoAzureError(TOKEN_AUDIENCE_MISSING_ERROR);
|
|
196
|
+
if (this.username && this.password) {
|
|
197
|
+
throw new MongoInvalidArgumentError(
|
|
198
|
+
`No password is allowed in ENVIRONMENT '${this.mechanismProperties.ENVIRONMENT}' for '${this.mechanism}'.`
|
|
199
|
+
);
|
|
193
200
|
}
|
|
194
201
|
|
|
195
202
|
if (
|
|
196
|
-
this.mechanismProperties.
|
|
197
|
-
|
|
203
|
+
(this.mechanismProperties.ENVIRONMENT === 'azure' ||
|
|
204
|
+
this.mechanismProperties.ENVIRONMENT === 'gcp') &&
|
|
205
|
+
!this.mechanismProperties.TOKEN_RESOURCE
|
|
198
206
|
) {
|
|
199
|
-
throw new MongoInvalidArgumentError(
|
|
200
|
-
`Currently only a PROVIDER_NAME in ${ALLOWED_PROVIDER_NAMES.join(
|
|
201
|
-
','
|
|
202
|
-
)} is supported for mechanism '${this.mechanism}'.`
|
|
203
|
-
);
|
|
207
|
+
throw new MongoInvalidArgumentError(TOKEN_RESOURCE_MISSING_ERROR);
|
|
204
208
|
}
|
|
205
209
|
|
|
206
210
|
if (
|
|
207
|
-
this.mechanismProperties.
|
|
208
|
-
!this.mechanismProperties.
|
|
211
|
+
this.mechanismProperties.ENVIRONMENT &&
|
|
212
|
+
!ALLOWED_ENVIRONMENT_NAMES.includes(this.mechanismProperties.ENVIRONMENT)
|
|
209
213
|
) {
|
|
210
214
|
throw new MongoInvalidArgumentError(
|
|
211
|
-
`
|
|
215
|
+
`Currently only a ENVIRONMENT in ${ALLOWED_ENVIRONMENT_NAMES.join(
|
|
216
|
+
','
|
|
217
|
+
)} is supported for mechanism '${this.mechanism}'.`
|
|
212
218
|
);
|
|
213
219
|
}
|
|
214
220
|
|
|
215
221
|
if (
|
|
216
|
-
!this.mechanismProperties.
|
|
217
|
-
!this.mechanismProperties.
|
|
222
|
+
!this.mechanismProperties.ENVIRONMENT &&
|
|
223
|
+
!this.mechanismProperties.OIDC_CALLBACK &&
|
|
224
|
+
!this.mechanismProperties.OIDC_HUMAN_CALLBACK
|
|
218
225
|
) {
|
|
219
226
|
throw new MongoInvalidArgumentError(
|
|
220
|
-
`Either a
|
|
227
|
+
`Either a ENVIRONMENT, OIDC_CALLBACK, or OIDC_HUMAN_CALLBACK must be specified for mechanism '${this.mechanism}'.`
|
|
221
228
|
);
|
|
222
229
|
}
|
|
223
230
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { MONGODB_ERROR_CODES, MongoError, MongoOIDCError } from '../../../error';
|
|
2
|
+
import { Timeout, TimeoutError } from '../../../timeout';
|
|
3
|
+
import { type Connection } from '../../connection';
|
|
4
|
+
import { type MongoCredentials } from '../mongo_credentials';
|
|
5
|
+
import {
|
|
6
|
+
OIDC_VERSION,
|
|
7
|
+
type OIDCCallbackFunction,
|
|
8
|
+
type OIDCCallbackParams,
|
|
9
|
+
type OIDCResponse
|
|
10
|
+
} from '../mongodb_oidc';
|
|
11
|
+
import { AUTOMATED_TIMEOUT_MS, CallbackWorkflow } from './callback_workflow';
|
|
12
|
+
import { type TokenCache } from './token_cache';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Class implementing behaviour for the non human callback workflow.
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export class AutomatedCallbackWorkflow extends CallbackWorkflow {
|
|
19
|
+
/**
|
|
20
|
+
* Instantiate the human callback workflow.
|
|
21
|
+
*/
|
|
22
|
+
constructor(cache: TokenCache, callback: OIDCCallbackFunction) {
|
|
23
|
+
super(cache, callback);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Execute the OIDC callback workflow.
|
|
28
|
+
*/
|
|
29
|
+
async execute(connection: Connection, credentials: MongoCredentials): Promise<void> {
|
|
30
|
+
// If there is a cached access token, try to authenticate with it. If
|
|
31
|
+
// authentication fails with an Authentication error (18),
|
|
32
|
+
// invalidate the access token, fetch a new access token, and try
|
|
33
|
+
// to authenticate again.
|
|
34
|
+
// If the server fails for any other reason, do not clear the cache.
|
|
35
|
+
if (this.cache.hasAccessToken) {
|
|
36
|
+
const token = this.cache.getAccessToken();
|
|
37
|
+
try {
|
|
38
|
+
return await this.finishAuthentication(connection, credentials, token);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (
|
|
41
|
+
error instanceof MongoError &&
|
|
42
|
+
error.code === MONGODB_ERROR_CODES.AuthenticationFailed
|
|
43
|
+
) {
|
|
44
|
+
this.cache.removeAccessToken();
|
|
45
|
+
return await this.execute(connection, credentials);
|
|
46
|
+
} else {
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const response = await this.fetchAccessToken(credentials);
|
|
52
|
+
this.cache.put(response);
|
|
53
|
+
connection.accessToken = response.accessToken;
|
|
54
|
+
await this.finishAuthentication(connection, credentials, response.accessToken);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Fetches the access token using the callback.
|
|
59
|
+
*/
|
|
60
|
+
protected async fetchAccessToken(credentials: MongoCredentials): Promise<OIDCResponse> {
|
|
61
|
+
const controller = new AbortController();
|
|
62
|
+
const params: OIDCCallbackParams = {
|
|
63
|
+
timeoutContext: controller.signal,
|
|
64
|
+
version: OIDC_VERSION
|
|
65
|
+
};
|
|
66
|
+
if (credentials.username) {
|
|
67
|
+
params.username = credentials.username;
|
|
68
|
+
}
|
|
69
|
+
const timeout = Timeout.expires(AUTOMATED_TIMEOUT_MS);
|
|
70
|
+
try {
|
|
71
|
+
return await Promise.race([this.executeAndValidateCallback(params), timeout]);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
if (TimeoutError.is(error)) {
|
|
74
|
+
controller.abort();
|
|
75
|
+
throw new MongoOIDCError(`OIDC callback timed out after ${AUTOMATED_TIMEOUT_MS}ms.`);
|
|
76
|
+
}
|
|
77
|
+
throw error;
|
|
78
|
+
} finally {
|
|
79
|
+
timeout.clear();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { addAzureParams, AZURE_BASE_URL } from '../../../client-side-encryption/providers/azure';
|
|
2
|
+
import { MongoAzureError } from '../../../error';
|
|
3
|
+
import { get } from '../../../utils';
|
|
4
|
+
import type { MongoCredentials } from '../mongo_credentials';
|
|
5
|
+
import { type AccessToken, MachineWorkflow } from './machine_workflow';
|
|
6
|
+
import { type TokenCache } from './token_cache';
|
|
7
|
+
|
|
8
|
+
/** Azure request headers. */
|
|
9
|
+
const AZURE_HEADERS = Object.freeze({ Metadata: 'true', Accept: 'application/json' });
|
|
10
|
+
|
|
11
|
+
/** Invalid endpoint result error. */
|
|
12
|
+
const ENDPOINT_RESULT_ERROR =
|
|
13
|
+
'Azure endpoint did not return a value with only access_token and expires_in properties';
|
|
14
|
+
|
|
15
|
+
/** Error for when the token audience is missing in the environment. */
|
|
16
|
+
const TOKEN_RESOURCE_MISSING_ERROR =
|
|
17
|
+
'TOKEN_RESOURCE must be set in the auth mechanism properties when ENVIRONMENT is azure.';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Device workflow implementation for Azure.
|
|
21
|
+
*
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
export class AzureMachineWorkflow extends MachineWorkflow {
|
|
25
|
+
/**
|
|
26
|
+
* Instantiate the machine workflow.
|
|
27
|
+
*/
|
|
28
|
+
constructor(cache: TokenCache) {
|
|
29
|
+
super(cache);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get the token from the environment.
|
|
34
|
+
*/
|
|
35
|
+
async getToken(credentials?: MongoCredentials): Promise<AccessToken> {
|
|
36
|
+
const tokenAudience = credentials?.mechanismProperties.TOKEN_RESOURCE;
|
|
37
|
+
const username = credentials?.username;
|
|
38
|
+
if (!tokenAudience) {
|
|
39
|
+
throw new MongoAzureError(TOKEN_RESOURCE_MISSING_ERROR);
|
|
40
|
+
}
|
|
41
|
+
const response = await getAzureTokenData(tokenAudience, username);
|
|
42
|
+
if (!isEndpointResultValid(response)) {
|
|
43
|
+
throw new MongoAzureError(ENDPOINT_RESULT_ERROR);
|
|
44
|
+
}
|
|
45
|
+
return response;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Hit the Azure endpoint to get the token data.
|
|
51
|
+
*/
|
|
52
|
+
async function getAzureTokenData(tokenAudience: string, username?: string): Promise<AccessToken> {
|
|
53
|
+
const url = new URL(AZURE_BASE_URL);
|
|
54
|
+
addAzureParams(url, tokenAudience, username);
|
|
55
|
+
const response = await get(url, {
|
|
56
|
+
headers: AZURE_HEADERS
|
|
57
|
+
});
|
|
58
|
+
if (response.status !== 200) {
|
|
59
|
+
throw new MongoAzureError(
|
|
60
|
+
`Status code ${response.status} returned from the Azure endpoint. Response body: ${response.body}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
const result = JSON.parse(response.body);
|
|
64
|
+
return {
|
|
65
|
+
access_token: result.access_token,
|
|
66
|
+
expires_in: Number(result.expires_in)
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Determines if a result returned from the endpoint is valid.
|
|
72
|
+
* This means the result is not nullish, contains the access_token required field
|
|
73
|
+
* and the expires_in required field.
|
|
74
|
+
*/
|
|
75
|
+
function isEndpointResultValid(
|
|
76
|
+
token: unknown
|
|
77
|
+
): token is { access_token: unknown; expires_in: unknown } {
|
|
78
|
+
if (token == null || typeof token !== 'object') return false;
|
|
79
|
+
return (
|
|
80
|
+
'access_token' in token &&
|
|
81
|
+
typeof token.access_token === 'string' &&
|
|
82
|
+
'expires_in' in token &&
|
|
83
|
+
typeof token.expires_in === 'number'
|
|
84
|
+
);
|
|
85
|
+
}
|