@azure/msal-browser 4.8.0 → 4.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/IPublicClientApplication.mjs +1 -1
- package/dist/app/PublicClientApplication.mjs +1 -1
- package/dist/app/PublicClientNext.mjs +1 -1
- package/dist/broker/nativeBroker/NativeMessageHandler.mjs +1 -1
- package/dist/broker/nativeBroker/NativeStatusCodes.mjs +1 -1
- package/dist/cache/AccountManager.mjs +1 -1
- package/dist/cache/AsyncMemoryStorage.mjs +1 -1
- package/dist/cache/BrowserCacheManager.d.ts +4 -41
- package/dist/cache/BrowserCacheManager.d.ts.map +1 -1
- package/dist/cache/BrowserCacheManager.mjs +18 -143
- package/dist/cache/BrowserCacheManager.mjs.map +1 -1
- package/dist/cache/CacheHelpers.mjs +1 -1
- package/dist/cache/CookieStorage.mjs +1 -1
- package/dist/cache/DatabaseStorage.mjs +1 -1
- package/dist/cache/LocalStorage.mjs +2 -2
- package/dist/cache/MemoryStorage.mjs +1 -1
- package/dist/cache/SessionStorage.mjs +1 -1
- package/dist/cache/TokenCache.mjs +1 -1
- package/dist/config/Configuration.mjs +5 -5
- package/dist/config/Configuration.mjs.map +1 -1
- package/dist/controllers/ControllerFactory.mjs +1 -1
- package/dist/controllers/NestedAppAuthController.d.ts +2 -2
- package/dist/controllers/NestedAppAuthController.d.ts.map +1 -1
- package/dist/controllers/NestedAppAuthController.mjs +1 -1
- package/dist/controllers/NestedAppAuthController.mjs.map +1 -1
- package/dist/controllers/StandardController.d.ts.map +1 -1
- package/dist/controllers/StandardController.mjs +28 -16
- package/dist/controllers/StandardController.mjs.map +1 -1
- package/dist/controllers/UnknownOperatingContextController.d.ts +2 -2
- package/dist/controllers/UnknownOperatingContextController.d.ts.map +1 -1
- package/dist/controllers/UnknownOperatingContextController.mjs +1 -1
- package/dist/controllers/UnknownOperatingContextController.mjs.map +1 -1
- package/dist/crypto/BrowserCrypto.d.ts +11 -0
- package/dist/crypto/BrowserCrypto.d.ts.map +1 -1
- package/dist/crypto/BrowserCrypto.mjs +68 -5
- package/dist/crypto/BrowserCrypto.mjs.map +1 -1
- package/dist/crypto/CryptoOps.mjs +1 -1
- package/dist/crypto/PkceGenerator.mjs +1 -1
- package/dist/crypto/SignedHttpRequest.mjs +1 -1
- package/dist/encode/Base64Decode.mjs +1 -1
- package/dist/encode/Base64Encode.mjs +1 -1
- package/dist/error/BrowserAuthError.d.ts +3 -5
- package/dist/error/BrowserAuthError.d.ts.map +1 -1
- package/dist/error/BrowserAuthError.mjs +5 -7
- package/dist/error/BrowserAuthError.mjs.map +1 -1
- package/dist/error/BrowserAuthErrorCodes.d.ts +3 -1
- package/dist/error/BrowserAuthErrorCodes.d.ts.map +1 -1
- package/dist/error/BrowserAuthErrorCodes.mjs +6 -4
- package/dist/error/BrowserAuthErrorCodes.mjs.map +1 -1
- package/dist/error/BrowserConfigurationAuthError.mjs +2 -2
- package/dist/error/BrowserConfigurationAuthErrorCodes.mjs +1 -1
- package/dist/error/NativeAuthError.mjs +1 -1
- package/dist/error/NativeAuthErrorCodes.mjs +1 -1
- package/dist/error/NestedAppAuthError.mjs +1 -1
- package/dist/event/EventHandler.mjs +1 -1
- package/dist/event/EventMessage.mjs +1 -1
- package/dist/event/EventType.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/interaction_client/BaseInteractionClient.mjs +1 -1
- package/dist/interaction_client/HybridSpaAuthorizationCodeClient.mjs +1 -1
- package/dist/interaction_client/NativeInteractionClient.d.ts.map +1 -1
- package/dist/interaction_client/NativeInteractionClient.mjs +1 -3
- package/dist/interaction_client/NativeInteractionClient.mjs.map +1 -1
- package/dist/interaction_client/PopupClient.d.ts +14 -1
- package/dist/interaction_client/PopupClient.d.ts.map +1 -1
- package/dist/interaction_client/PopupClient.mjs +65 -64
- package/dist/interaction_client/PopupClient.mjs.map +1 -1
- package/dist/interaction_client/RedirectClient.d.ts +20 -3
- package/dist/interaction_client/RedirectClient.d.ts.map +1 -1
- package/dist/interaction_client/RedirectClient.mjs +132 -76
- package/dist/interaction_client/RedirectClient.mjs.map +1 -1
- package/dist/interaction_client/SilentAuthCodeClient.d.ts.map +1 -1
- package/dist/interaction_client/SilentAuthCodeClient.mjs +1 -1
- package/dist/interaction_client/SilentAuthCodeClient.mjs.map +1 -1
- package/dist/interaction_client/SilentCacheClient.mjs +1 -1
- package/dist/interaction_client/SilentIframeClient.d.ts +13 -3
- package/dist/interaction_client/SilentIframeClient.d.ts.map +1 -1
- package/dist/interaction_client/SilentIframeClient.mjs +57 -44
- package/dist/interaction_client/SilentIframeClient.mjs.map +1 -1
- package/dist/interaction_client/SilentRefreshClient.mjs +1 -1
- package/dist/interaction_client/StandardInteractionClient.d.ts +2 -3
- package/dist/interaction_client/StandardInteractionClient.d.ts.map +1 -1
- package/dist/interaction_client/StandardInteractionClient.mjs +1 -1
- package/dist/interaction_client/StandardInteractionClient.mjs.map +1 -1
- package/dist/interaction_handler/InteractionHandler.d.ts +4 -5
- package/dist/interaction_handler/InteractionHandler.d.ts.map +1 -1
- package/dist/interaction_handler/InteractionHandler.mjs +1 -1
- package/dist/interaction_handler/InteractionHandler.mjs.map +1 -1
- package/dist/interaction_handler/SilentHandler.d.ts +4 -2
- package/dist/interaction_handler/SilentHandler.d.ts.map +1 -1
- package/dist/interaction_handler/SilentHandler.mjs +15 -5
- package/dist/interaction_handler/SilentHandler.mjs.map +1 -1
- package/dist/naa/BridgeError.mjs +1 -1
- package/dist/naa/BridgeProxy.mjs +1 -1
- package/dist/naa/BridgeStatusCode.mjs +1 -1
- package/dist/naa/mapping/NestedAppAuthAdapter.mjs +2 -2
- package/dist/navigation/NavigationClient.mjs +1 -1
- package/dist/network/FetchClient.mjs +1 -1
- package/dist/operatingcontext/BaseOperatingContext.mjs +1 -1
- package/dist/operatingcontext/NestedAppOperatingContext.mjs +1 -1
- package/dist/operatingcontext/StandardOperatingContext.mjs +1 -1
- package/dist/operatingcontext/UnknownOperatingContext.mjs +1 -1
- package/dist/packageMetadata.d.ts +1 -1
- package/dist/packageMetadata.mjs +2 -2
- package/dist/protocol/Authorize.d.ts +53 -1
- package/dist/protocol/Authorize.d.ts.map +1 -1
- package/dist/protocol/Authorize.mjs +147 -4
- package/dist/protocol/Authorize.mjs.map +1 -1
- package/dist/request/AuthorizationUrlRequest.d.ts +2 -4
- package/dist/request/AuthorizationUrlRequest.d.ts.map +1 -1
- package/dist/request/PopupRequest.d.ts +1 -1
- package/dist/request/PopupRequest.d.ts.map +1 -1
- package/dist/request/RedirectRequest.d.ts +1 -1
- package/dist/request/RedirectRequest.d.ts.map +1 -1
- package/dist/request/RequestHelpers.mjs +1 -1
- package/dist/request/SsoSilentRequest.d.ts +1 -1
- package/dist/request/SsoSilentRequest.d.ts.map +1 -1
- package/dist/response/ResponseHandler.mjs +1 -1
- package/dist/telemetry/BrowserPerformanceClient.mjs +1 -1
- package/dist/telemetry/BrowserPerformanceMeasurement.mjs +1 -1
- package/dist/utils/BrowserConstants.d.ts +1 -10
- package/dist/utils/BrowserConstants.d.ts.map +1 -1
- package/dist/utils/BrowserConstants.mjs +2 -15
- package/dist/utils/BrowserConstants.mjs.map +1 -1
- package/dist/utils/BrowserProtocolUtils.mjs +1 -1
- package/dist/utils/BrowserUtils.mjs +1 -1
- package/lib/msal-browser.cjs +1588 -1555
- package/lib/msal-browser.cjs.map +1 -1
- package/lib/msal-browser.js +1588 -1555
- package/lib/msal-browser.js.map +1 -1
- package/lib/msal-browser.min.js +68 -67
- package/lib/types/cache/BrowserCacheManager.d.ts +4 -41
- package/lib/types/cache/BrowserCacheManager.d.ts.map +1 -1
- package/lib/types/controllers/NestedAppAuthController.d.ts +2 -2
- package/lib/types/controllers/NestedAppAuthController.d.ts.map +1 -1
- package/lib/types/controllers/StandardController.d.ts.map +1 -1
- package/lib/types/controllers/UnknownOperatingContextController.d.ts +2 -2
- package/lib/types/controllers/UnknownOperatingContextController.d.ts.map +1 -1
- package/lib/types/crypto/BrowserCrypto.d.ts +11 -0
- package/lib/types/crypto/BrowserCrypto.d.ts.map +1 -1
- package/lib/types/error/BrowserAuthError.d.ts +3 -5
- package/lib/types/error/BrowserAuthError.d.ts.map +1 -1
- package/lib/types/error/BrowserAuthErrorCodes.d.ts +3 -1
- package/lib/types/error/BrowserAuthErrorCodes.d.ts.map +1 -1
- package/lib/types/interaction_client/NativeInteractionClient.d.ts.map +1 -1
- package/lib/types/interaction_client/PopupClient.d.ts +14 -1
- package/lib/types/interaction_client/PopupClient.d.ts.map +1 -1
- package/lib/types/interaction_client/RedirectClient.d.ts +20 -3
- package/lib/types/interaction_client/RedirectClient.d.ts.map +1 -1
- package/lib/types/interaction_client/SilentAuthCodeClient.d.ts.map +1 -1
- package/lib/types/interaction_client/SilentIframeClient.d.ts +13 -3
- package/lib/types/interaction_client/SilentIframeClient.d.ts.map +1 -1
- package/lib/types/interaction_client/StandardInteractionClient.d.ts +2 -3
- package/lib/types/interaction_client/StandardInteractionClient.d.ts.map +1 -1
- package/lib/types/interaction_handler/InteractionHandler.d.ts +4 -5
- package/lib/types/interaction_handler/InteractionHandler.d.ts.map +1 -1
- package/lib/types/interaction_handler/SilentHandler.d.ts +4 -2
- package/lib/types/interaction_handler/SilentHandler.d.ts.map +1 -1
- package/lib/types/packageMetadata.d.ts +1 -1
- package/lib/types/protocol/Authorize.d.ts +53 -1
- package/lib/types/protocol/Authorize.d.ts.map +1 -1
- package/lib/types/request/AuthorizationUrlRequest.d.ts +2 -4
- package/lib/types/request/AuthorizationUrlRequest.d.ts.map +1 -1
- package/lib/types/request/PopupRequest.d.ts +1 -1
- package/lib/types/request/PopupRequest.d.ts.map +1 -1
- package/lib/types/request/RedirectRequest.d.ts +1 -1
- package/lib/types/request/RedirectRequest.d.ts.map +1 -1
- package/lib/types/request/SsoSilentRequest.d.ts +1 -1
- package/lib/types/request/SsoSilentRequest.d.ts.map +1 -1
- package/lib/types/utils/BrowserConstants.d.ts +1 -10
- package/lib/types/utils/BrowserConstants.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/cache/BrowserCacheManager.ts +30 -205
- package/src/config/Configuration.ts +2 -2
- package/src/controllers/NestedAppAuthController.ts +2 -0
- package/src/controllers/StandardController.ts +35 -24
- package/src/controllers/UnknownOperatingContextController.ts +2 -0
- package/src/crypto/BrowserCrypto.ts +91 -2
- package/src/error/BrowserAuthError.ts +6 -8
- package/src/error/BrowserAuthErrorCodes.ts +3 -1
- package/src/interaction_client/NativeInteractionClient.ts +0 -2
- package/src/interaction_client/PopupClient.ts +163 -119
- package/src/interaction_client/RedirectClient.ts +258 -140
- package/src/interaction_client/SilentAuthCodeClient.ts +2 -2
- package/src/interaction_client/SilentIframeClient.ts +154 -99
- package/src/interaction_client/StandardInteractionClient.ts +3 -3
- package/src/interaction_handler/InteractionHandler.ts +4 -4
- package/src/interaction_handler/SilentHandler.ts +31 -2
- package/src/packageMetadata.ts +1 -1
- package/src/protocol/Authorize.ts +356 -2
- package/src/request/AuthorizationUrlRequest.ts +3 -5
- package/src/request/PopupRequest.ts +1 -0
- package/src/request/RedirectRequest.ts +1 -0
- package/src/request/SsoSilentRequest.ts +1 -0
- package/src/utils/BrowserConstants.ts +1 -10
- package/dist/interaction_handler/RedirectHandler.d.ts +0 -33
- package/dist/interaction_handler/RedirectHandler.d.ts.map +0 -1
- package/dist/interaction_handler/RedirectHandler.mjs +0 -144
- package/dist/interaction_handler/RedirectHandler.mjs.map +0 -1
- package/lib/types/interaction_handler/RedirectHandler.d.ts +0 -33
- package/lib/types/interaction_handler/RedirectHandler.d.ts.map +0 -1
- package/src/interaction_handler/RedirectHandler.ts +0 -252
package/lib/msal-browser.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/*! @azure/msal-browser v4.
|
|
1
|
+
/*! @azure/msal-browser v4.9.1 2025-03-26 */
|
|
2
2
|
'use strict';
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
|
-
/*! @azure/msal-common v15.
|
|
5
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6
6
|
/*
|
|
7
7
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
8
8
|
* Licensed under the MIT License.
|
|
@@ -37,11 +37,8 @@ const Constants = {
|
|
|
37
37
|
PROFILE_SCOPE: "profile",
|
|
38
38
|
OFFLINE_ACCESS_SCOPE: "offline_access",
|
|
39
39
|
EMAIL_SCOPE: "email",
|
|
40
|
-
// Default response type for authorization code flow
|
|
41
|
-
CODE_RESPONSE_TYPE: "code",
|
|
42
40
|
CODE_GRANT_TYPE: "authorization_code",
|
|
43
41
|
RT_GRANT_TYPE: "refresh_token",
|
|
44
|
-
FRAGMENT_RESPONSE_MODE: "fragment",
|
|
45
42
|
S256_CODE_CHALLENGE_METHOD: "S256",
|
|
46
43
|
URL_FORM_CONTENT_TYPE: "application/x-www-form-urlencoded;charset=utf-8",
|
|
47
44
|
AUTHORIZATION_PENDING: "authorization_pending",
|
|
@@ -61,31 +58,14 @@ const Constants = {
|
|
|
61
58
|
"login.microsoft.com",
|
|
62
59
|
"sts.windows.net",
|
|
63
60
|
],
|
|
64
|
-
TOKEN_RESPONSE_TYPE: "token",
|
|
65
|
-
ID_TOKEN_RESPONSE_TYPE: "id_token",
|
|
66
61
|
SHR_NONCE_VALIDITY: 240,
|
|
67
62
|
INVALID_INSTANCE: "invalid_instance",
|
|
68
63
|
};
|
|
69
64
|
const HttpStatus = {
|
|
70
|
-
SUCCESS: 200,
|
|
71
|
-
SUCCESS_RANGE_START: 200,
|
|
72
|
-
SUCCESS_RANGE_END: 299,
|
|
73
|
-
REDIRECT: 302,
|
|
74
|
-
CLIENT_ERROR: 400,
|
|
75
65
|
CLIENT_ERROR_RANGE_START: 400,
|
|
76
|
-
BAD_REQUEST: 400,
|
|
77
|
-
UNAUTHORIZED: 401,
|
|
78
|
-
NOT_FOUND: 404,
|
|
79
|
-
REQUEST_TIMEOUT: 408,
|
|
80
|
-
TOO_MANY_REQUESTS: 429,
|
|
81
66
|
CLIENT_ERROR_RANGE_END: 499,
|
|
82
|
-
SERVER_ERROR: 500,
|
|
83
67
|
SERVER_ERROR_RANGE_START: 500,
|
|
84
|
-
|
|
85
|
-
GATEWAY_TIMEOUT: 504,
|
|
86
|
-
SERVER_ERROR_RANGE_END: 599,
|
|
87
|
-
MULTI_SIDED_ERROR: 600,
|
|
88
|
-
};
|
|
68
|
+
SERVER_ERROR_RANGE_END: 599};
|
|
89
69
|
const OIDC_DEFAULT_SCOPES = [
|
|
90
70
|
Constants.OPENID_SCOPE,
|
|
91
71
|
Constants.PROFILE_SCOPE,
|
|
@@ -146,8 +126,16 @@ const CodeChallengeMethodValues = {
|
|
|
146
126
|
PLAIN: "plain",
|
|
147
127
|
S256: "S256",
|
|
148
128
|
};
|
|
129
|
+
/**
|
|
130
|
+
* Allowed values for response_type
|
|
131
|
+
*/
|
|
132
|
+
const OAuthResponseType = {
|
|
133
|
+
CODE: "code",
|
|
134
|
+
IDTOKEN_TOKEN_REFRESHTOKEN: "id_token token refresh_token",
|
|
135
|
+
};
|
|
149
136
|
/**
|
|
150
137
|
* allowed values for server response type
|
|
138
|
+
* @deprecated Use ResponseMode instead
|
|
151
139
|
*/
|
|
152
140
|
const ServerResponseType = {
|
|
153
141
|
QUERY: "query",
|
|
@@ -157,28 +145,19 @@ const ServerResponseType = {
|
|
|
157
145
|
* allowed values for response_mode
|
|
158
146
|
*/
|
|
159
147
|
const ResponseMode = {
|
|
160
|
-
|
|
161
|
-
FORM_POST: "form_post",
|
|
162
|
-
};
|
|
148
|
+
QUERY: "query"};
|
|
163
149
|
/**
|
|
164
150
|
* allowed grant_type
|
|
165
151
|
*/
|
|
166
152
|
const GrantType = {
|
|
167
|
-
IMPLICIT_GRANT: "implicit",
|
|
168
153
|
AUTHORIZATION_CODE_GRANT: "authorization_code",
|
|
169
|
-
|
|
170
|
-
RESOURCE_OWNER_PASSWORD_GRANT: "password",
|
|
171
|
-
REFRESH_TOKEN_GRANT: "refresh_token",
|
|
172
|
-
DEVICE_CODE_GRANT: "device_code",
|
|
173
|
-
JWT_BEARER: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
174
|
-
};
|
|
154
|
+
REFRESH_TOKEN_GRANT: "refresh_token"};
|
|
175
155
|
/**
|
|
176
156
|
* Account types in Cache
|
|
177
157
|
*/
|
|
178
158
|
const CacheAccountType = {
|
|
179
159
|
MSSTS_ACCOUNT_TYPE: "MSSTS",
|
|
180
160
|
ADFS_ACCOUNT_TYPE: "ADFS",
|
|
181
|
-
MSAV1_ACCOUNT_TYPE: "MSA",
|
|
182
161
|
GENERIC_ACCOUNT_TYPE: "Generic", // NTLM, Kerberos, FBA, Basic etc
|
|
183
162
|
};
|
|
184
163
|
/**
|
|
@@ -215,7 +194,6 @@ const AuthorityMetadataSource = {
|
|
|
215
194
|
};
|
|
216
195
|
const SERVER_TELEM_CONSTANTS = {
|
|
217
196
|
SCHEMA_VERSION: 5,
|
|
218
|
-
MAX_CUR_HEADER_BYTES: 80,
|
|
219
197
|
MAX_LAST_HEADER_BYTES: 330,
|
|
220
198
|
MAX_CACHED_ERRORS: 50,
|
|
221
199
|
CACHE_KEY: "server-telemetry",
|
|
@@ -270,9 +248,7 @@ const RegionDiscoverySources = {
|
|
|
270
248
|
* Region Discovery Outcomes
|
|
271
249
|
*/
|
|
272
250
|
const RegionDiscoveryOutcomes = {
|
|
273
|
-
CONFIGURED_MATCHES_DETECTED: "1",
|
|
274
251
|
CONFIGURED_NO_AUTO_DETECTION: "2",
|
|
275
|
-
CONFIGURED_NOT_DETECTED: "3",
|
|
276
252
|
AUTO_DETECTION_REQUESTED_SUCCESSFUL: "4",
|
|
277
253
|
AUTO_DETECTION_REQUESTED_FAILED: "5",
|
|
278
254
|
};
|
|
@@ -299,7 +275,7 @@ const JsonWebTokenTypes = {
|
|
|
299
275
|
// Token renewal offset default in seconds
|
|
300
276
|
const DEFAULT_TOKEN_RENEWAL_OFFSET_SEC = 300;
|
|
301
277
|
|
|
302
|
-
/*! @azure/msal-common v15.
|
|
278
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
303
279
|
/*
|
|
304
280
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
305
281
|
* Licensed under the MIT License.
|
|
@@ -316,7 +292,7 @@ var AuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
|
316
292
|
unexpectedError: unexpectedError
|
|
317
293
|
});
|
|
318
294
|
|
|
319
|
-
/*! @azure/msal-common v15.
|
|
295
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
320
296
|
|
|
321
297
|
/*
|
|
322
298
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -365,7 +341,7 @@ function createAuthError(code, additionalMessage) {
|
|
|
365
341
|
: AuthErrorMessages[code]);
|
|
366
342
|
}
|
|
367
343
|
|
|
368
|
-
/*! @azure/msal-common v15.
|
|
344
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
369
345
|
/*
|
|
370
346
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
371
347
|
* Licensed under the MIT License.
|
|
@@ -463,7 +439,7 @@ var ClientAuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
|
463
439
|
userTimeoutReached: userTimeoutReached
|
|
464
440
|
});
|
|
465
441
|
|
|
466
|
-
/*! @azure/msal-common v15.
|
|
442
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
467
443
|
|
|
468
444
|
/*
|
|
469
445
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -715,7 +691,7 @@ function createClientAuthError(errorCode, additionalMessage) {
|
|
|
715
691
|
return new ClientAuthError(errorCode, additionalMessage);
|
|
716
692
|
}
|
|
717
693
|
|
|
718
|
-
/*! @azure/msal-common v15.
|
|
694
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
719
695
|
|
|
720
696
|
/*
|
|
721
697
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -754,7 +730,7 @@ const DEFAULT_CRYPTO_IMPLEMENTATION = {
|
|
|
754
730
|
},
|
|
755
731
|
};
|
|
756
732
|
|
|
757
|
-
/*! @azure/msal-common v15.
|
|
733
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
758
734
|
|
|
759
735
|
/*
|
|
760
736
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -945,12 +921,12 @@ class Logger {
|
|
|
945
921
|
}
|
|
946
922
|
}
|
|
947
923
|
|
|
948
|
-
/*! @azure/msal-common v15.
|
|
924
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
949
925
|
/* eslint-disable header/header */
|
|
950
926
|
const name$1 = "@azure/msal-common";
|
|
951
|
-
const version$1 = "15.
|
|
927
|
+
const version$1 = "15.4.0";
|
|
952
928
|
|
|
953
|
-
/*! @azure/msal-common v15.
|
|
929
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
954
930
|
/*
|
|
955
931
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
956
932
|
* Licensed under the MIT License.
|
|
@@ -970,7 +946,7 @@ const AzureCloudInstance = {
|
|
|
970
946
|
AzureUsGovernment: "https://login.microsoftonline.us",
|
|
971
947
|
};
|
|
972
948
|
|
|
973
|
-
/*! @azure/msal-common v15.
|
|
949
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
974
950
|
|
|
975
951
|
/*
|
|
976
952
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1031,7 +1007,7 @@ function checkMaxAge(authTime, maxAge) {
|
|
|
1031
1007
|
}
|
|
1032
1008
|
}
|
|
1033
1009
|
|
|
1034
|
-
/*! @azure/msal-common v15.
|
|
1010
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
1035
1011
|
/*
|
|
1036
1012
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
1037
1013
|
* Licensed under the MIT License.
|
|
@@ -1086,7 +1062,7 @@ function wasClockTurnedBack(cachedAt) {
|
|
|
1086
1062
|
return cachedAtSec > nowSeconds();
|
|
1087
1063
|
}
|
|
1088
1064
|
|
|
1089
|
-
/*! @azure/msal-common v15.
|
|
1065
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
1090
1066
|
|
|
1091
1067
|
/*
|
|
1092
1068
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1413,7 +1389,7 @@ function isAuthorityMetadataExpired(metadata) {
|
|
|
1413
1389
|
return metadata.expiresAt <= nowSeconds();
|
|
1414
1390
|
}
|
|
1415
1391
|
|
|
1416
|
-
/*! @azure/msal-common v15.
|
|
1392
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
1417
1393
|
/*
|
|
1418
1394
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
1419
1395
|
* Licensed under the MIT License.
|
|
@@ -1467,7 +1443,7 @@ var ClientConfigurationErrorCodes = /*#__PURE__*/Object.freeze({
|
|
|
1467
1443
|
urlParseError: urlParseError
|
|
1468
1444
|
});
|
|
1469
1445
|
|
|
1470
|
-
/*! @azure/msal-common v15.
|
|
1446
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
1471
1447
|
|
|
1472
1448
|
/*
|
|
1473
1449
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1605,7 +1581,7 @@ function createClientConfigurationError(errorCode) {
|
|
|
1605
1581
|
return new ClientConfigurationError(errorCode);
|
|
1606
1582
|
}
|
|
1607
1583
|
|
|
1608
|
-
/*! @azure/msal-common v15.
|
|
1584
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
1609
1585
|
/*
|
|
1610
1586
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
1611
1587
|
* Licensed under the MIT License.
|
|
@@ -1702,7 +1678,7 @@ class StringUtils {
|
|
|
1702
1678
|
}
|
|
1703
1679
|
}
|
|
1704
1680
|
|
|
1705
|
-
/*! @azure/msal-common v15.
|
|
1681
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
1706
1682
|
|
|
1707
1683
|
/*
|
|
1708
1684
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1893,7 +1869,7 @@ class ScopeSet {
|
|
|
1893
1869
|
}
|
|
1894
1870
|
}
|
|
1895
1871
|
|
|
1896
|
-
/*! @azure/msal-common v15.
|
|
1872
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
1897
1873
|
|
|
1898
1874
|
/*
|
|
1899
1875
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1933,7 +1909,7 @@ function buildClientInfoFromHomeAccountId(homeAccountId) {
|
|
|
1933
1909
|
};
|
|
1934
1910
|
}
|
|
1935
1911
|
|
|
1936
|
-
/*! @azure/msal-common v15.
|
|
1912
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
1937
1913
|
/*
|
|
1938
1914
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
1939
1915
|
* Licensed under the MIT License.
|
|
@@ -2012,7 +1988,7 @@ function updateAccountTenantProfileData(baseAccountInfo, tenantProfile, idTokenC
|
|
|
2012
1988
|
return updatedAccountInfo;
|
|
2013
1989
|
}
|
|
2014
1990
|
|
|
2015
|
-
/*! @azure/msal-common v15.
|
|
1991
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
2016
1992
|
/*
|
|
2017
1993
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2018
1994
|
* Licensed under the MIT License.
|
|
@@ -2027,7 +2003,7 @@ const AuthorityType = {
|
|
|
2027
2003
|
Ciam: 3,
|
|
2028
2004
|
};
|
|
2029
2005
|
|
|
2030
|
-
/*! @azure/msal-common v15.
|
|
2006
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
2031
2007
|
/*
|
|
2032
2008
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2033
2009
|
* Licensed under the MIT License.
|
|
@@ -2049,7 +2025,7 @@ function getTenantIdFromIdTokenClaims(idTokenClaims) {
|
|
|
2049
2025
|
return null;
|
|
2050
2026
|
}
|
|
2051
2027
|
|
|
2052
|
-
/*! @azure/msal-common v15.
|
|
2028
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
2053
2029
|
/*
|
|
2054
2030
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2055
2031
|
* Licensed under the MIT License.
|
|
@@ -2058,11 +2034,22 @@ function getTenantIdFromIdTokenClaims(idTokenClaims) {
|
|
|
2058
2034
|
* Protocol modes supported by MSAL.
|
|
2059
2035
|
*/
|
|
2060
2036
|
const ProtocolMode = {
|
|
2037
|
+
/**
|
|
2038
|
+
* Auth Code + PKCE with Entra ID (formerly AAD) specific optimizations and features
|
|
2039
|
+
*/
|
|
2061
2040
|
AAD: "AAD",
|
|
2041
|
+
/**
|
|
2042
|
+
* Auth Code + PKCE without Entra ID specific optimizations and features. For use only with non-Microsoft owned authorities.
|
|
2043
|
+
* Support is limited for this mode.
|
|
2044
|
+
*/
|
|
2062
2045
|
OIDC: "OIDC",
|
|
2046
|
+
/**
|
|
2047
|
+
* Encrypted Authorize Response (EAR) with Entra ID specific optimizations and features
|
|
2048
|
+
*/
|
|
2049
|
+
EAR: "EAR",
|
|
2063
2050
|
};
|
|
2064
2051
|
|
|
2065
|
-
/*! @azure/msal-common v15.
|
|
2052
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
2066
2053
|
|
|
2067
2054
|
/*
|
|
2068
2055
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2158,11 +2145,11 @@ class AccountEntity {
|
|
|
2158
2145
|
if (authority.authorityType === AuthorityType.Adfs) {
|
|
2159
2146
|
account.authorityType = CacheAccountType.ADFS_ACCOUNT_TYPE;
|
|
2160
2147
|
}
|
|
2161
|
-
else if (authority.protocolMode === ProtocolMode.
|
|
2162
|
-
account.authorityType = CacheAccountType.
|
|
2148
|
+
else if (authority.protocolMode === ProtocolMode.OIDC) {
|
|
2149
|
+
account.authorityType = CacheAccountType.GENERIC_ACCOUNT_TYPE;
|
|
2163
2150
|
}
|
|
2164
2151
|
else {
|
|
2165
|
-
account.authorityType = CacheAccountType.
|
|
2152
|
+
account.authorityType = CacheAccountType.MSSTS_ACCOUNT_TYPE;
|
|
2166
2153
|
}
|
|
2167
2154
|
let clientInfo;
|
|
2168
2155
|
if (accountDetails.clientInfo && base64Decode) {
|
|
@@ -2305,7 +2292,7 @@ class AccountEntity {
|
|
|
2305
2292
|
}
|
|
2306
2293
|
}
|
|
2307
2294
|
|
|
2308
|
-
/*! @azure/msal-common v15.
|
|
2295
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
2309
2296
|
|
|
2310
2297
|
/*
|
|
2311
2298
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2340,6 +2327,7 @@ function getDeserializedResponse(responseString) {
|
|
|
2340
2327
|
const deserializedHash = Object.fromEntries(new URLSearchParams(normalizedResponse));
|
|
2341
2328
|
// Check for known response properties
|
|
2342
2329
|
if (deserializedHash.code ||
|
|
2330
|
+
deserializedHash.ear_jwe ||
|
|
2343
2331
|
deserializedHash.error ||
|
|
2344
2332
|
deserializedHash.error_description ||
|
|
2345
2333
|
deserializedHash.state) {
|
|
@@ -2362,7 +2350,7 @@ function mapToQueryString(parameters) {
|
|
|
2362
2350
|
return queryParameterArray.join("&");
|
|
2363
2351
|
}
|
|
2364
2352
|
|
|
2365
|
-
/*! @azure/msal-common v15.
|
|
2353
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
2366
2354
|
|
|
2367
2355
|
/*
|
|
2368
2356
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2526,7 +2514,7 @@ class UrlString {
|
|
|
2526
2514
|
}
|
|
2527
2515
|
}
|
|
2528
2516
|
|
|
2529
|
-
/*! @azure/msal-common v15.
|
|
2517
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
2530
2518
|
|
|
2531
2519
|
/*
|
|
2532
2520
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2557,7 +2545,6 @@ const rawMetdataJSON = {
|
|
|
2557
2545
|
},
|
|
2558
2546
|
},
|
|
2559
2547
|
instanceDiscoveryMetadata: {
|
|
2560
|
-
tenant_discovery_endpoint: "https://{canonicalAuthority}/v2.0/.well-known/openid-configuration",
|
|
2561
2548
|
metadata: [
|
|
2562
2549
|
{
|
|
2563
2550
|
preferred_network: "login.microsoftonline.com",
|
|
@@ -2666,7 +2653,7 @@ function getCloudDiscoveryMetadataFromNetworkResponse(response, authorityHost) {
|
|
|
2666
2653
|
return null;
|
|
2667
2654
|
}
|
|
2668
2655
|
|
|
2669
|
-
/*! @azure/msal-common v15.
|
|
2656
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
2670
2657
|
/*
|
|
2671
2658
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2672
2659
|
* Licensed under the MIT License.
|
|
@@ -2674,7 +2661,7 @@ function getCloudDiscoveryMetadataFromNetworkResponse(response, authorityHost) {
|
|
|
2674
2661
|
const cacheQuotaExceededErrorCode = "cache_quota_exceeded";
|
|
2675
2662
|
const cacheUnknownErrorCode = "cache_error_unknown";
|
|
2676
2663
|
|
|
2677
|
-
/*! @azure/msal-common v15.
|
|
2664
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
2678
2665
|
|
|
2679
2666
|
/*
|
|
2680
2667
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2701,7 +2688,7 @@ class CacheError extends Error {
|
|
|
2701
2688
|
}
|
|
2702
2689
|
}
|
|
2703
2690
|
|
|
2704
|
-
/*! @azure/msal-common v15.
|
|
2691
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
2705
2692
|
|
|
2706
2693
|
/*
|
|
2707
2694
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -3886,7 +3873,7 @@ class DefaultStorageClass extends CacheManager {
|
|
|
3886
3873
|
}
|
|
3887
3874
|
}
|
|
3888
3875
|
|
|
3889
|
-
/*! @azure/msal-common v15.
|
|
3876
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
3890
3877
|
|
|
3891
3878
|
/*
|
|
3892
3879
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -3985,7 +3972,7 @@ function isOidcProtocolMode(config) {
|
|
|
3985
3972
|
return (config.authOptions.authority.options.protocolMode === ProtocolMode.OIDC);
|
|
3986
3973
|
}
|
|
3987
3974
|
|
|
3988
|
-
/*! @azure/msal-common v15.
|
|
3975
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
3989
3976
|
/*
|
|
3990
3977
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3991
3978
|
* Licensed under the MIT License.
|
|
@@ -3995,7 +3982,7 @@ const CcsCredentialType = {
|
|
|
3995
3982
|
UPN: "UPN",
|
|
3996
3983
|
};
|
|
3997
3984
|
|
|
3998
|
-
/*! @azure/msal-common v15.
|
|
3985
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
3999
3986
|
/*
|
|
4000
3987
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4001
3988
|
* Licensed under the MIT License.
|
|
@@ -4041,9 +4028,11 @@ const DOMAIN_HINT = "domain_hint";
|
|
|
4041
4028
|
const X_CLIENT_EXTRA_SKU = "x-client-xtra-sku";
|
|
4042
4029
|
const BROKER_CLIENT_ID = "brk_client_id";
|
|
4043
4030
|
const BROKER_REDIRECT_URI = "brk_redirect_uri";
|
|
4044
|
-
const INSTANCE_AWARE = "instance_aware";
|
|
4031
|
+
const INSTANCE_AWARE = "instance_aware";
|
|
4032
|
+
const EAR_JWK = "ear_jwk";
|
|
4033
|
+
const EAR_JWE_CRYPTO = "ear_jwe_crypto";
|
|
4045
4034
|
|
|
4046
|
-
/*! @azure/msal-common v15.
|
|
4035
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
4047
4036
|
|
|
4048
4037
|
/*
|
|
4049
4038
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -4062,10 +4051,12 @@ function instrumentBrokerParams(parameters, correlationId, performanceClient) {
|
|
|
4062
4051
|
}
|
|
4063
4052
|
}
|
|
4064
4053
|
/**
|
|
4065
|
-
*
|
|
4054
|
+
* Add the given response_type
|
|
4055
|
+
* @param parameters
|
|
4056
|
+
* @param responseType
|
|
4066
4057
|
*/
|
|
4067
|
-
function
|
|
4068
|
-
parameters.set(RESPONSE_TYPE,
|
|
4058
|
+
function addResponseType(parameters, responseType) {
|
|
4059
|
+
parameters.set(RESPONSE_TYPE, responseType);
|
|
4069
4060
|
}
|
|
4070
4061
|
/**
|
|
4071
4062
|
* add response_mode. defaults to query.
|
|
@@ -4396,9 +4387,20 @@ function addBrokerParameters(parameters, brokerClientId, brokerRedirectUri) {
|
|
|
4396
4387
|
if (!parameters.has(BROKER_REDIRECT_URI)) {
|
|
4397
4388
|
parameters.set(BROKER_REDIRECT_URI, brokerRedirectUri);
|
|
4398
4389
|
}
|
|
4390
|
+
}
|
|
4391
|
+
/**
|
|
4392
|
+
* Add EAR (Encrypted Authorize Response) request parameters
|
|
4393
|
+
* @param parameters
|
|
4394
|
+
* @param jwk
|
|
4395
|
+
*/
|
|
4396
|
+
function addEARParameters(parameters, jwk) {
|
|
4397
|
+
parameters.set(EAR_JWK, encodeURIComponent(jwk));
|
|
4398
|
+
// ear_jwe_crypto will always have value: {"alg":"dir","enc":"A256GCM"} so we can hardcode this
|
|
4399
|
+
const jweCryptoB64Encoded = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0";
|
|
4400
|
+
parameters.set(EAR_JWE_CRYPTO, jweCryptoB64Encoded);
|
|
4399
4401
|
}
|
|
4400
4402
|
|
|
4401
|
-
/*! @azure/msal-common v15.
|
|
4403
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
4402
4404
|
/*
|
|
4403
4405
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4404
4406
|
* Licensed under the MIT License.
|
|
@@ -4410,7 +4412,7 @@ function isOpenIdConfigResponse(response) {
|
|
|
4410
4412
|
response.hasOwnProperty("jwks_uri"));
|
|
4411
4413
|
}
|
|
4412
4414
|
|
|
4413
|
-
/*! @azure/msal-common v15.
|
|
4415
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
4414
4416
|
/*
|
|
4415
4417
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4416
4418
|
* Licensed under the MIT License.
|
|
@@ -4420,7 +4422,7 @@ function isCloudInstanceDiscoveryResponse(response) {
|
|
|
4420
4422
|
response.hasOwnProperty("metadata"));
|
|
4421
4423
|
}
|
|
4422
4424
|
|
|
4423
|
-
/*! @azure/msal-common v15.
|
|
4425
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
4424
4426
|
/*
|
|
4425
4427
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4426
4428
|
* Licensed under the MIT License.
|
|
@@ -4430,7 +4432,7 @@ function isCloudInstanceDiscoveryErrorResponse(response) {
|
|
|
4430
4432
|
response.hasOwnProperty("error_description"));
|
|
4431
4433
|
}
|
|
4432
4434
|
|
|
4433
|
-
/*! @azure/msal-common v15.
|
|
4435
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
4434
4436
|
/*
|
|
4435
4437
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4436
4438
|
* Licensed under the MIT License.
|
|
@@ -4616,6 +4618,9 @@ const PerformanceEvents = {
|
|
|
4616
4618
|
*/
|
|
4617
4619
|
HandleCodeResponseFromServer: "handleCodeResponseFromServer",
|
|
4618
4620
|
HandleCodeResponse: "handleCodeResponse",
|
|
4621
|
+
HandleResponseEar: "handleResponseEar",
|
|
4622
|
+
HandleResponsePlatformBroker: "handleResponsePlatformBroker",
|
|
4623
|
+
HandleResponseCode: "handleResponseCode",
|
|
4619
4624
|
UpdateTokenEndpointAuthority: "updateTokenEndpointAuthority",
|
|
4620
4625
|
/**
|
|
4621
4626
|
* APIs in Authorization Code Client (msal-common)
|
|
@@ -4682,6 +4687,8 @@ const PerformanceEvents = {
|
|
|
4682
4687
|
UrlEncodeArr: "urlEncodeArr",
|
|
4683
4688
|
Encrypt: "encrypt",
|
|
4684
4689
|
Decrypt: "decrypt",
|
|
4690
|
+
GenerateEarKey: "generateEarKey",
|
|
4691
|
+
DecryptEarResponse: "decryptEarResponse",
|
|
4685
4692
|
};
|
|
4686
4693
|
const PerformanceEventAbbreviations = new Map([
|
|
4687
4694
|
[PerformanceEvents.AcquireTokenByCode, "ATByCode"],
|
|
@@ -4799,6 +4806,12 @@ const PerformanceEventAbbreviations = new Map([
|
|
|
4799
4806
|
"HandleCodeResFromServer",
|
|
4800
4807
|
],
|
|
4801
4808
|
[PerformanceEvents.HandleCodeResponse, "HandleCodeResp"],
|
|
4809
|
+
[PerformanceEvents.HandleResponseEar, "HandleRespEar"],
|
|
4810
|
+
[PerformanceEvents.HandleResponseCode, "HandleRespCode"],
|
|
4811
|
+
[
|
|
4812
|
+
PerformanceEvents.HandleResponsePlatformBroker,
|
|
4813
|
+
"HandleRespPlatBroker",
|
|
4814
|
+
],
|
|
4802
4815
|
[PerformanceEvents.UpdateTokenEndpointAuthority, "UpdTEndpointAuth"],
|
|
4803
4816
|
[PerformanceEvents.AuthClientAcquireToken, "AuthClientAT"],
|
|
4804
4817
|
[PerformanceEvents.AuthClientExecuteTokenRequest, "AuthClientExecTReq"],
|
|
@@ -4901,6 +4914,8 @@ const PerformanceEventAbbreviations = new Map([
|
|
|
4901
4914
|
[PerformanceEvents.UrlEncodeArr, "urlEncArr"],
|
|
4902
4915
|
[PerformanceEvents.Encrypt, "encrypt"],
|
|
4903
4916
|
[PerformanceEvents.Decrypt, "decrypt"],
|
|
4917
|
+
[PerformanceEvents.GenerateEarKey, "genEarKey"],
|
|
4918
|
+
[PerformanceEvents.DecryptEarResponse, "decryptEarResp"],
|
|
4904
4919
|
]);
|
|
4905
4920
|
/**
|
|
4906
4921
|
* State of the performance event.
|
|
@@ -4909,7 +4924,6 @@ const PerformanceEventAbbreviations = new Map([
|
|
|
4909
4924
|
* @enum {number}
|
|
4910
4925
|
*/
|
|
4911
4926
|
const PerformanceEventStatus = {
|
|
4912
|
-
NotStarted: 0,
|
|
4913
4927
|
InProgress: 1,
|
|
4914
4928
|
Completed: 2,
|
|
4915
4929
|
};
|
|
@@ -4930,7 +4944,7 @@ const IntFields = new Set([
|
|
|
4930
4944
|
"encryptedCacheExpiredCount",
|
|
4931
4945
|
]);
|
|
4932
4946
|
|
|
4933
|
-
/*! @azure/msal-common v15.
|
|
4947
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
4934
4948
|
/*
|
|
4935
4949
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4936
4950
|
* Licensed under the MIT License.
|
|
@@ -5026,7 +5040,7 @@ const invokeAsync = (callback, eventName, logger, telemetryClient, correlationId
|
|
|
5026
5040
|
};
|
|
5027
5041
|
};
|
|
5028
5042
|
|
|
5029
|
-
/*! @azure/msal-common v15.
|
|
5043
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
5030
5044
|
|
|
5031
5045
|
/*
|
|
5032
5046
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -5135,7 +5149,7 @@ RegionDiscovery.IMDS_OPTIONS = {
|
|
|
5135
5149
|
},
|
|
5136
5150
|
};
|
|
5137
5151
|
|
|
5138
|
-
/*! @azure/msal-common v15.
|
|
5152
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
5139
5153
|
|
|
5140
5154
|
/*
|
|
5141
5155
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -5313,7 +5327,7 @@ class Authority {
|
|
|
5313
5327
|
return (authorityUri.PathSegments.length === 1 &&
|
|
5314
5328
|
!Authority.reservedTenantDomains.has(authorityUri.PathSegments[0]) &&
|
|
5315
5329
|
this.getAuthorityType(authorityUri) === AuthorityType.Default &&
|
|
5316
|
-
this.protocolMode
|
|
5330
|
+
this.protocolMode !== ProtocolMode.OIDC);
|
|
5317
5331
|
}
|
|
5318
5332
|
/**
|
|
5319
5333
|
* Replaces tenant in url path with current tenant. Defaults to common.
|
|
@@ -5360,7 +5374,7 @@ class Authority {
|
|
|
5360
5374
|
const canonicalAuthorityHost = this.hostnameAndPort;
|
|
5361
5375
|
if (this.canonicalAuthority.endsWith("v2.0/") ||
|
|
5362
5376
|
this.authorityType === AuthorityType.Adfs ||
|
|
5363
|
-
(this.protocolMode
|
|
5377
|
+
(this.protocolMode === ProtocolMode.OIDC &&
|
|
5364
5378
|
!this.isAliasOfKnownMicrosoftAuthority(canonicalAuthorityHost))) {
|
|
5365
5379
|
return `${this.canonicalAuthority}.well-known/openid-configuration`;
|
|
5366
5380
|
}
|
|
@@ -5974,7 +5988,7 @@ function buildStaticAuthorityOptions(authOptions) {
|
|
|
5974
5988
|
};
|
|
5975
5989
|
}
|
|
5976
5990
|
|
|
5977
|
-
/*! @azure/msal-common v15.
|
|
5991
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
5978
5992
|
|
|
5979
5993
|
/*
|
|
5980
5994
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6005,7 +6019,7 @@ async function createDiscoveredInstance(authorityUri, networkClient, cacheManage
|
|
|
6005
6019
|
}
|
|
6006
6020
|
}
|
|
6007
6021
|
|
|
6008
|
-
/*! @azure/msal-common v15.
|
|
6022
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6009
6023
|
|
|
6010
6024
|
/*
|
|
6011
6025
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6024,7 +6038,7 @@ class ServerError extends AuthError {
|
|
|
6024
6038
|
}
|
|
6025
6039
|
}
|
|
6026
6040
|
|
|
6027
|
-
/*! @azure/msal-common v15.
|
|
6041
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6028
6042
|
/*
|
|
6029
6043
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
6030
6044
|
* Licensed under the MIT License.
|
|
@@ -6045,7 +6059,7 @@ function getRequestThumbprint(clientId, request, homeAccountId) {
|
|
|
6045
6059
|
};
|
|
6046
6060
|
}
|
|
6047
6061
|
|
|
6048
|
-
/*! @azure/msal-common v15.
|
|
6062
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6049
6063
|
|
|
6050
6064
|
/*
|
|
6051
6065
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6132,7 +6146,7 @@ class ThrottlingUtils {
|
|
|
6132
6146
|
}
|
|
6133
6147
|
}
|
|
6134
6148
|
|
|
6135
|
-
/*! @azure/msal-common v15.
|
|
6149
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6136
6150
|
|
|
6137
6151
|
/*
|
|
6138
6152
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6162,7 +6176,7 @@ function createNetworkError(error, httpStatus, responseHeaders) {
|
|
|
6162
6176
|
return new NetworkError(error, httpStatus, responseHeaders);
|
|
6163
6177
|
}
|
|
6164
6178
|
|
|
6165
|
-
/*! @azure/msal-common v15.
|
|
6179
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6166
6180
|
|
|
6167
6181
|
/*
|
|
6168
6182
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6310,7 +6324,7 @@ class BaseClient {
|
|
|
6310
6324
|
}
|
|
6311
6325
|
}
|
|
6312
6326
|
|
|
6313
|
-
/*! @azure/msal-common v15.
|
|
6327
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6314
6328
|
/*
|
|
6315
6329
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
6316
6330
|
* Licensed under the MIT License.
|
|
@@ -6336,7 +6350,7 @@ var InteractionRequiredAuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
|
6336
6350
|
refreshTokenExpired: refreshTokenExpired
|
|
6337
6351
|
});
|
|
6338
6352
|
|
|
6339
|
-
/*! @azure/msal-common v15.
|
|
6353
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6340
6354
|
|
|
6341
6355
|
/*
|
|
6342
6356
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6424,7 +6438,7 @@ function createInteractionRequiredAuthError(errorCode) {
|
|
|
6424
6438
|
return new InteractionRequiredAuthError(errorCode, InteractionRequiredAuthErrorMessages[errorCode]);
|
|
6425
6439
|
}
|
|
6426
6440
|
|
|
6427
|
-
/*! @azure/msal-common v15.
|
|
6441
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6428
6442
|
|
|
6429
6443
|
/*
|
|
6430
6444
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6496,16 +6510,14 @@ class ProtocolUtils {
|
|
|
6496
6510
|
}
|
|
6497
6511
|
}
|
|
6498
6512
|
|
|
6499
|
-
/*! @azure/msal-common v15.
|
|
6513
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6500
6514
|
|
|
6501
6515
|
/*
|
|
6502
6516
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
6503
6517
|
* Licensed under the MIT License.
|
|
6504
6518
|
*/
|
|
6505
6519
|
const KeyLocation = {
|
|
6506
|
-
SW: "sw"
|
|
6507
|
-
UHW: "uhw",
|
|
6508
|
-
};
|
|
6520
|
+
SW: "sw"};
|
|
6509
6521
|
/** @internal */
|
|
6510
6522
|
class PopTokenGenerator {
|
|
6511
6523
|
constructor(cryptoUtils, performanceClient) {
|
|
@@ -6580,7 +6592,7 @@ class PopTokenGenerator {
|
|
|
6580
6592
|
}
|
|
6581
6593
|
}
|
|
6582
6594
|
|
|
6583
|
-
/*! @azure/msal-common v15.
|
|
6595
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6584
6596
|
/*
|
|
6585
6597
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
6586
6598
|
* Licensed under the MIT License.
|
|
@@ -6607,7 +6619,7 @@ class PopTokenGenerator {
|
|
|
6607
6619
|
}
|
|
6608
6620
|
}
|
|
6609
6621
|
|
|
6610
|
-
/*! @azure/msal-common v15.
|
|
6622
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6611
6623
|
|
|
6612
6624
|
/*
|
|
6613
6625
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6938,7 +6950,7 @@ function buildAccountToCache(cacheStorage, authority, homeAccountId, base64Decod
|
|
|
6938
6950
|
return baseAccount;
|
|
6939
6951
|
}
|
|
6940
6952
|
|
|
6941
|
-
/*! @azure/msal-common v15.
|
|
6953
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
6942
6954
|
|
|
6943
6955
|
/*
|
|
6944
6956
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7005,7 +7017,7 @@ class RequestValidator {
|
|
|
7005
7017
|
}
|
|
7006
7018
|
}
|
|
7007
7019
|
|
|
7008
|
-
/*! @azure/msal-common v15.
|
|
7020
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
7009
7021
|
/*
|
|
7010
7022
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
7011
7023
|
* Licensed under the MIT License.
|
|
@@ -7023,7 +7035,7 @@ async function getClientAssertion(clientAssertion, clientId, tokenEndpoint) {
|
|
|
7023
7035
|
}
|
|
7024
7036
|
}
|
|
7025
7037
|
|
|
7026
|
-
/*! @azure/msal-common v15.
|
|
7038
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
7027
7039
|
|
|
7028
7040
|
/*
|
|
7029
7041
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7256,7 +7268,7 @@ class AuthorizationCodeClient extends BaseClient {
|
|
|
7256
7268
|
}
|
|
7257
7269
|
}
|
|
7258
7270
|
|
|
7259
|
-
/*! @azure/msal-common v15.
|
|
7271
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
7260
7272
|
|
|
7261
7273
|
/*
|
|
7262
7274
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7465,7 +7477,7 @@ class RefreshTokenClient extends BaseClient {
|
|
|
7465
7477
|
}
|
|
7466
7478
|
}
|
|
7467
7479
|
|
|
7468
|
-
/*! @azure/msal-common v15.
|
|
7480
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
7469
7481
|
|
|
7470
7482
|
/*
|
|
7471
7483
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7563,7 +7575,7 @@ class SilentFlowClient extends BaseClient {
|
|
|
7563
7575
|
}
|
|
7564
7576
|
}
|
|
7565
7577
|
|
|
7566
|
-
/*! @azure/msal-common v15.
|
|
7578
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
7567
7579
|
|
|
7568
7580
|
/*
|
|
7569
7581
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7578,7 +7590,7 @@ const StubbedNetworkModule = {
|
|
|
7578
7590
|
},
|
|
7579
7591
|
};
|
|
7580
7592
|
|
|
7581
|
-
/*! @azure/msal-common v15.
|
|
7593
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
7582
7594
|
|
|
7583
7595
|
/*
|
|
7584
7596
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7707,10 +7719,10 @@ function getStandardAuthorizeRequestParameters(authOptions, request, logger, per
|
|
|
7707
7719
|
if (request.embeddedClientId) {
|
|
7708
7720
|
addBrokerParameters(parameters, authOptions.clientId, authOptions.redirectUri);
|
|
7709
7721
|
}
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7722
|
+
// If extraQueryParameters includes instance_aware its value will be added when extraQueryParameters are added
|
|
7723
|
+
if (authOptions.instanceAware &&
|
|
7724
|
+
(!request.extraQueryParameters ||
|
|
7725
|
+
!Object.keys(request.extraQueryParameters).includes(INSTANCE_AWARE))) {
|
|
7714
7726
|
addInstanceAware(parameters);
|
|
7715
7727
|
}
|
|
7716
7728
|
return parameters;
|
|
@@ -7802,7 +7814,7 @@ function extractLoginHint(account) {
|
|
|
7802
7814
|
return account.idTokenClaims?.login_hint || null;
|
|
7803
7815
|
}
|
|
7804
7816
|
|
|
7805
|
-
/*! @azure/msal-common v15.
|
|
7817
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
7806
7818
|
|
|
7807
7819
|
/*
|
|
7808
7820
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7860,7 +7872,7 @@ class AuthenticationHeaderParser {
|
|
|
7860
7872
|
}
|
|
7861
7873
|
}
|
|
7862
7874
|
|
|
7863
|
-
/*! @azure/msal-common v15.
|
|
7875
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
7864
7876
|
|
|
7865
7877
|
/*
|
|
7866
7878
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8123,7 +8135,7 @@ class ServerTelemetryManager {
|
|
|
8123
8135
|
}
|
|
8124
8136
|
}
|
|
8125
8137
|
|
|
8126
|
-
/*! @azure/msal-common v15.
|
|
8138
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
8127
8139
|
/*
|
|
8128
8140
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
8129
8141
|
* Licensed under the MIT License.
|
|
@@ -8131,7 +8143,7 @@ class ServerTelemetryManager {
|
|
|
8131
8143
|
const missingKidError = "missing_kid_error";
|
|
8132
8144
|
const missingAlgError = "missing_alg_error";
|
|
8133
8145
|
|
|
8134
|
-
/*! @azure/msal-common v15.
|
|
8146
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
8135
8147
|
|
|
8136
8148
|
/*
|
|
8137
8149
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8156,7 +8168,7 @@ function createJoseHeaderError(code) {
|
|
|
8156
8168
|
return new JoseHeaderError(code, JoseHeaderErrorMessages[code]);
|
|
8157
8169
|
}
|
|
8158
8170
|
|
|
8159
|
-
/*! @azure/msal-common v15.
|
|
8171
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
8160
8172
|
|
|
8161
8173
|
/*
|
|
8162
8174
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8196,7 +8208,7 @@ class JoseHeader {
|
|
|
8196
8208
|
}
|
|
8197
8209
|
}
|
|
8198
8210
|
|
|
8199
|
-
/*! @azure/msal-common v15.
|
|
8211
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
8200
8212
|
|
|
8201
8213
|
/*
|
|
8202
8214
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8275,7 +8287,7 @@ class StubPerformanceClient {
|
|
|
8275
8287
|
}
|
|
8276
8288
|
}
|
|
8277
8289
|
|
|
8278
|
-
/*! @azure/msal-common v15.
|
|
8290
|
+
/*! @azure/msal-common v15.4.0 2025-03-26 */
|
|
8279
8291
|
|
|
8280
8292
|
/*
|
|
8281
8293
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8889,6 +8901,8 @@ class PerformanceClient {
|
|
|
8889
8901
|
* Licensed under the MIT License.
|
|
8890
8902
|
*/
|
|
8891
8903
|
const pkceNotCreated = "pkce_not_created";
|
|
8904
|
+
const earJwkEmpty = "ear_jwk_empty";
|
|
8905
|
+
const earJweEmpty = "ear_jwe_empty";
|
|
8892
8906
|
const cryptoNonExistent = "crypto_nonexistent";
|
|
8893
8907
|
const emptyNavigateUri = "empty_navigate_uri";
|
|
8894
8908
|
const hashEmptyError = "hash_empty_error";
|
|
@@ -8911,7 +8925,6 @@ const noAccountError = "no_account_error";
|
|
|
8911
8925
|
const silentPromptValueError = "silent_prompt_value_error";
|
|
8912
8926
|
const noTokenRequestCacheError = "no_token_request_cache_error";
|
|
8913
8927
|
const unableToParseTokenRequestCacheError = "unable_to_parse_token_request_cache_error";
|
|
8914
|
-
const noCachedAuthorityError = "no_cached_authority_error";
|
|
8915
8928
|
const authRequestNotSetError = "auth_request_not_set_error";
|
|
8916
8929
|
const invalidCacheType = "invalid_cache_type";
|
|
8917
8930
|
const nonBrowserEnvironment = "non_browser_environment";
|
|
@@ -8935,7 +8948,8 @@ const nativePromptNotSupported = "native_prompt_not_supported";
|
|
|
8935
8948
|
const invalidBase64String = "invalid_base64_string";
|
|
8936
8949
|
const invalidPopTokenRequest = "invalid_pop_token_request";
|
|
8937
8950
|
const failedToBuildHeaders = "failed_to_build_headers";
|
|
8938
|
-
const failedToParseHeaders = "failed_to_parse_headers";
|
|
8951
|
+
const failedToParseHeaders = "failed_to_parse_headers";
|
|
8952
|
+
const failedToDecryptEarResponse = "failed_to_decrypt_ear_response";
|
|
8939
8953
|
|
|
8940
8954
|
var BrowserAuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
8941
8955
|
__proto__: null,
|
|
@@ -8948,9 +8962,12 @@ var BrowserAuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
|
8948
8962
|
cryptoNonExistent: cryptoNonExistent,
|
|
8949
8963
|
databaseNotOpen: databaseNotOpen,
|
|
8950
8964
|
databaseUnavailable: databaseUnavailable,
|
|
8965
|
+
earJweEmpty: earJweEmpty,
|
|
8966
|
+
earJwkEmpty: earJwkEmpty,
|
|
8951
8967
|
emptyNavigateUri: emptyNavigateUri,
|
|
8952
8968
|
emptyWindowError: emptyWindowError,
|
|
8953
8969
|
failedToBuildHeaders: failedToBuildHeaders,
|
|
8970
|
+
failedToDecryptEarResponse: failedToDecryptEarResponse,
|
|
8954
8971
|
failedToParseHeaders: failedToParseHeaders,
|
|
8955
8972
|
failedToParseResponse: failedToParseResponse,
|
|
8956
8973
|
getRequestFailed: getRequestFailed,
|
|
@@ -8968,7 +8985,6 @@ var BrowserAuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
|
8968
8985
|
nativeHandshakeTimeout: nativeHandshakeTimeout,
|
|
8969
8986
|
nativePromptNotSupported: nativePromptNotSupported,
|
|
8970
8987
|
noAccountError: noAccountError,
|
|
8971
|
-
noCachedAuthorityError: noCachedAuthorityError,
|
|
8972
8988
|
noNetworkConnectivity: noNetworkConnectivity,
|
|
8973
8989
|
noStateInHash: noStateInHash,
|
|
8974
8990
|
noTokenRequestCacheError: noTokenRequestCacheError,
|
|
@@ -8999,6 +9015,8 @@ const ErrorLink = "For more visit: aka.ms/msaljs/browser-errors";
|
|
|
8999
9015
|
*/
|
|
9000
9016
|
const BrowserAuthErrorMessages = {
|
|
9001
9017
|
[pkceNotCreated]: "The PKCE code challenge and verifier could not be generated.",
|
|
9018
|
+
[earJwkEmpty]: "No EAR encryption key provided. This is unexpected.",
|
|
9019
|
+
[earJweEmpty]: "Server response does not contain ear_jwe property. This is unexpected.",
|
|
9002
9020
|
[cryptoNonExistent]: "The crypto object or function is not available.",
|
|
9003
9021
|
[emptyNavigateUri]: "Navigation URI is empty. Please check stack trace for more info.",
|
|
9004
9022
|
[hashEmptyError]: `Hash value cannot be processed because it is empty. Please verify that your redirectUri is not clearing the hash. ${ErrorLink}`,
|
|
@@ -9021,7 +9039,6 @@ const BrowserAuthErrorMessages = {
|
|
|
9021
9039
|
[silentPromptValueError]: "The value given for the prompt value is not valid for silent requests - must be set to 'none' or 'no_session'.",
|
|
9022
9040
|
[noTokenRequestCacheError]: "No token request found in cache.",
|
|
9023
9041
|
[unableToParseTokenRequestCacheError]: "The cached token request could not be parsed.",
|
|
9024
|
-
[noCachedAuthorityError]: "No cached authority found.",
|
|
9025
9042
|
[authRequestNotSetError]: "Auth Request not set. Please ensure initiateAuthRequest was called from the InteractionHandler",
|
|
9026
9043
|
[invalidCacheType]: "Invalid cache type",
|
|
9027
9044
|
[nonBrowserEnvironment]: "Login and token requests are not supported in non-browser environments.",
|
|
@@ -9046,6 +9063,7 @@ const BrowserAuthErrorMessages = {
|
|
|
9046
9063
|
[invalidPopTokenRequest]: "Invalid PoP token request. The request should not have both a popKid value and signPopToken set to true.",
|
|
9047
9064
|
[failedToBuildHeaders]: "Failed to build request headers object.",
|
|
9048
9065
|
[failedToParseHeaders]: "Failed to parse response headers",
|
|
9066
|
+
[failedToDecryptEarResponse]: "Failed to decrypt ear response",
|
|
9049
9067
|
};
|
|
9050
9068
|
/**
|
|
9051
9069
|
* BrowserAuthErrorMessage class containing string constants used by error codes and messages.
|
|
@@ -9148,10 +9166,6 @@ const BrowserAuthErrorMessage = {
|
|
|
9148
9166
|
code: unableToParseTokenRequestCacheError,
|
|
9149
9167
|
desc: BrowserAuthErrorMessages[unableToParseTokenRequestCacheError],
|
|
9150
9168
|
},
|
|
9151
|
-
noCachedAuthorityError: {
|
|
9152
|
-
code: noCachedAuthorityError,
|
|
9153
|
-
desc: BrowserAuthErrorMessages[noCachedAuthorityError],
|
|
9154
|
-
},
|
|
9155
9169
|
authRequestNotSet: {
|
|
9156
9170
|
code: authRequestNotSetError,
|
|
9157
9171
|
desc: BrowserAuthErrorMessages[authRequestNotSetError],
|
|
@@ -9263,10 +9277,6 @@ function createBrowserAuthError(errorCode, subError) {
|
|
|
9263
9277
|
* Constants
|
|
9264
9278
|
*/
|
|
9265
9279
|
const BrowserConstants = {
|
|
9266
|
-
/**
|
|
9267
|
-
* Interaction in progress cache value
|
|
9268
|
-
*/
|
|
9269
|
-
INTERACTION_IN_PROGRESS_VALUE: "interaction_in_progress",
|
|
9270
9280
|
/**
|
|
9271
9281
|
* Invalid grant error code
|
|
9272
9282
|
*/
|
|
@@ -9319,21 +9329,12 @@ const HTTP_REQUEST_TYPE = {
|
|
|
9319
9329
|
* Temporary cache keys for MSAL, deleted after any request.
|
|
9320
9330
|
*/
|
|
9321
9331
|
const TemporaryCacheKeys = {
|
|
9322
|
-
AUTHORITY: "authority",
|
|
9323
|
-
ACQUIRE_TOKEN_ACCOUNT: "acquireToken.account",
|
|
9324
|
-
SESSION_STATE: "session.state",
|
|
9325
|
-
REQUEST_STATE: "request.state",
|
|
9326
|
-
NONCE_IDTOKEN: "nonce.id_token",
|
|
9327
9332
|
ORIGIN_URI: "request.origin",
|
|
9328
|
-
RENEW_STATUS: "token.renew.status",
|
|
9329
9333
|
URL_HASH: "urlHash",
|
|
9330
9334
|
REQUEST_PARAMS: "request.params",
|
|
9331
|
-
|
|
9335
|
+
VERIFIER: "code.verifier",
|
|
9332
9336
|
INTERACTION_STATUS_KEY: "interaction.status",
|
|
9333
|
-
CCS_CREDENTIAL: "ccs.credential",
|
|
9334
|
-
CORRELATION_ID: "request.correlationId",
|
|
9335
9337
|
NATIVE_REQUEST: "request.native",
|
|
9336
|
-
REDIRECT_CONTEXT: "request.redirect.context",
|
|
9337
9338
|
};
|
|
9338
9339
|
const StaticCacheKeys = {
|
|
9339
9340
|
ACCOUNT_KEYS: "msal.account.keys",
|
|
@@ -9703,6 +9704,69 @@ async function importJwk(key, extractable, usages) {
|
|
|
9703
9704
|
async function sign(key, data) {
|
|
9704
9705
|
return window.crypto.subtle.sign(keygenAlgorithmOptions, key, data);
|
|
9705
9706
|
}
|
|
9707
|
+
/**
|
|
9708
|
+
* Generates Base64 encoded jwk used in the Encrypted Authorize Response (EAR) flow
|
|
9709
|
+
*/
|
|
9710
|
+
async function generateEarKey() {
|
|
9711
|
+
const key = await generateBaseKey();
|
|
9712
|
+
const keyStr = urlEncodeArr(new Uint8Array(key));
|
|
9713
|
+
const jwk = {
|
|
9714
|
+
alg: "dir",
|
|
9715
|
+
kty: "oct",
|
|
9716
|
+
k: keyStr,
|
|
9717
|
+
};
|
|
9718
|
+
return base64Encode(JSON.stringify(jwk));
|
|
9719
|
+
}
|
|
9720
|
+
/**
|
|
9721
|
+
* Parses earJwk for encryption key and returns CryptoKey object
|
|
9722
|
+
* @param earJwk
|
|
9723
|
+
* @returns
|
|
9724
|
+
*/
|
|
9725
|
+
async function importEarKey(earJwk) {
|
|
9726
|
+
const b64DecodedJwk = base64Decode(earJwk);
|
|
9727
|
+
const jwkJson = JSON.parse(b64DecodedJwk);
|
|
9728
|
+
const rawKey = jwkJson.k;
|
|
9729
|
+
const keyBuffer = base64DecToArr(rawKey);
|
|
9730
|
+
return window.crypto.subtle.importKey(RAW, keyBuffer, AES_GCM, false, [
|
|
9731
|
+
DECRYPT,
|
|
9732
|
+
]);
|
|
9733
|
+
}
|
|
9734
|
+
/**
|
|
9735
|
+
* Decrypt ear_jwe response returned in the Encrypted Authorize Response (EAR) flow
|
|
9736
|
+
* @param earJwk
|
|
9737
|
+
* @param earJwe
|
|
9738
|
+
* @returns
|
|
9739
|
+
*/
|
|
9740
|
+
async function decryptEarResponse(earJwk, earJwe) {
|
|
9741
|
+
const earJweParts = earJwe.split(".");
|
|
9742
|
+
if (earJweParts.length !== 5) {
|
|
9743
|
+
throw createBrowserAuthError(failedToDecryptEarResponse, "jwe_length");
|
|
9744
|
+
}
|
|
9745
|
+
const key = await importEarKey(earJwk).catch(() => {
|
|
9746
|
+
throw createBrowserAuthError(failedToDecryptEarResponse, "import_key");
|
|
9747
|
+
});
|
|
9748
|
+
try {
|
|
9749
|
+
const header = new TextEncoder().encode(earJweParts[0]);
|
|
9750
|
+
const iv = base64DecToArr(earJweParts[2]);
|
|
9751
|
+
const ciphertext = base64DecToArr(earJweParts[3]);
|
|
9752
|
+
const tag = base64DecToArr(earJweParts[4]);
|
|
9753
|
+
const tagLengthBits = tag.byteLength * 8;
|
|
9754
|
+
// Concat ciphertext and tag
|
|
9755
|
+
const encryptedData = new Uint8Array(ciphertext.length + tag.length);
|
|
9756
|
+
encryptedData.set(ciphertext);
|
|
9757
|
+
encryptedData.set(tag, ciphertext.length);
|
|
9758
|
+
const decryptedData = await window.crypto.subtle.decrypt({
|
|
9759
|
+
name: AES_GCM,
|
|
9760
|
+
iv: iv,
|
|
9761
|
+
tagLength: tagLengthBits,
|
|
9762
|
+
additionalData: header,
|
|
9763
|
+
}, key, encryptedData);
|
|
9764
|
+
return new TextDecoder().decode(decryptedData);
|
|
9765
|
+
}
|
|
9766
|
+
catch (e) {
|
|
9767
|
+
throw createBrowserAuthError(failedToDecryptEarResponse, "decrypt");
|
|
9768
|
+
}
|
|
9769
|
+
}
|
|
9706
9770
|
/**
|
|
9707
9771
|
* Generates symmetric base encryption key. This may be stored as all encryption/decryption keys will be derived from this one.
|
|
9708
9772
|
*/
|
|
@@ -10288,9 +10352,9 @@ function buildConfiguration({ auth: userInputAuth, cache: userInputCache, system
|
|
|
10288
10352
|
const logger = new Logger(providedSystemOptions.loggerOptions);
|
|
10289
10353
|
logger.warning(JSON.stringify(createClientConfigurationError(cannotSetOIDCOptions)));
|
|
10290
10354
|
}
|
|
10291
|
-
// Throw an error if user has set allowPlatformBroker to true
|
|
10355
|
+
// Throw an error if user has set allowPlatformBroker to true with OIDC protocol mode
|
|
10292
10356
|
if (userInputAuth?.protocolMode &&
|
|
10293
|
-
userInputAuth.protocolMode
|
|
10357
|
+
userInputAuth.protocolMode === ProtocolMode.OIDC &&
|
|
10294
10358
|
providedSystemOptions?.allowPlatformBroker) {
|
|
10295
10359
|
throw createClientConfigurationError(cannotAllowPlatformBroker);
|
|
10296
10360
|
}
|
|
@@ -10312,7 +10376,7 @@ function buildConfiguration({ auth: userInputAuth, cache: userInputCache, system
|
|
|
10312
10376
|
|
|
10313
10377
|
/* eslint-disable header/header */
|
|
10314
10378
|
const name = "@azure/msal-browser";
|
|
10315
|
-
const version = "4.
|
|
10379
|
+
const version = "4.9.1";
|
|
10316
10380
|
|
|
10317
10381
|
/*
|
|
10318
10382
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -11633,28 +11697,6 @@ class SessionStorage {
|
|
|
11633
11697
|
}
|
|
11634
11698
|
}
|
|
11635
11699
|
|
|
11636
|
-
/*
|
|
11637
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
11638
|
-
* Licensed under the MIT License.
|
|
11639
|
-
*/
|
|
11640
|
-
/**
|
|
11641
|
-
* Extracts the BrowserStateObject from the state string.
|
|
11642
|
-
* @param browserCrypto
|
|
11643
|
-
* @param state
|
|
11644
|
-
*/
|
|
11645
|
-
function extractBrowserRequestState(browserCrypto, state) {
|
|
11646
|
-
if (!state) {
|
|
11647
|
-
return null;
|
|
11648
|
-
}
|
|
11649
|
-
try {
|
|
11650
|
-
const requestStateObj = ProtocolUtils.parseRequestState(browserCrypto, state);
|
|
11651
|
-
return requestStateObj.libraryState.meta;
|
|
11652
|
-
}
|
|
11653
|
-
catch (e) {
|
|
11654
|
-
throw createClientAuthError(invalidState);
|
|
11655
|
-
}
|
|
11656
|
-
}
|
|
11657
|
-
|
|
11658
11700
|
/*
|
|
11659
11701
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
11660
11702
|
* Licensed under the MIT License.
|
|
@@ -12354,177 +12396,53 @@ class BrowserCacheManager extends CacheManager {
|
|
|
12354
12396
|
}
|
|
12355
12397
|
return JSON.stringify(key);
|
|
12356
12398
|
}
|
|
12357
|
-
/**
|
|
12358
|
-
* Create authorityKey to cache authority
|
|
12359
|
-
* @param state
|
|
12360
|
-
*/
|
|
12361
|
-
generateAuthorityKey(stateString) {
|
|
12362
|
-
const { libraryState: { id: stateId }, } = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString);
|
|
12363
|
-
return this.generateCacheKey(`${TemporaryCacheKeys.AUTHORITY}.${stateId}`);
|
|
12364
|
-
}
|
|
12365
|
-
/**
|
|
12366
|
-
* Create Nonce key to cache nonce
|
|
12367
|
-
* @param state
|
|
12368
|
-
*/
|
|
12369
|
-
generateNonceKey(stateString) {
|
|
12370
|
-
const { libraryState: { id: stateId }, } = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString);
|
|
12371
|
-
return this.generateCacheKey(`${TemporaryCacheKeys.NONCE_IDTOKEN}.${stateId}`);
|
|
12372
|
-
}
|
|
12373
|
-
/**
|
|
12374
|
-
* Creates full cache key for the request state
|
|
12375
|
-
* @param stateString State string for the request
|
|
12376
|
-
*/
|
|
12377
|
-
generateStateKey(stateString) {
|
|
12378
|
-
// Use the library state id to key temp storage for uniqueness for multiple concurrent requests
|
|
12379
|
-
const { libraryState: { id: stateId }, } = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString);
|
|
12380
|
-
return this.generateCacheKey(`${TemporaryCacheKeys.REQUEST_STATE}.${stateId}`);
|
|
12381
|
-
}
|
|
12382
|
-
/**
|
|
12383
|
-
* Gets the cached authority based on the cached state. Returns empty if no cached state found.
|
|
12384
|
-
*/
|
|
12385
|
-
getCachedAuthority(cachedState) {
|
|
12386
|
-
const stateCacheKey = this.generateStateKey(cachedState);
|
|
12387
|
-
const state = this.getTemporaryCache(stateCacheKey);
|
|
12388
|
-
if (!state) {
|
|
12389
|
-
return null;
|
|
12390
|
-
}
|
|
12391
|
-
const authorityCacheKey = this.generateAuthorityKey(state);
|
|
12392
|
-
return this.getTemporaryCache(authorityCacheKey);
|
|
12393
|
-
}
|
|
12394
|
-
/**
|
|
12395
|
-
* Updates account, authority, and state in cache
|
|
12396
|
-
* @param serverAuthenticationRequest
|
|
12397
|
-
* @param account
|
|
12398
|
-
*/
|
|
12399
|
-
updateCacheEntries(state, nonce, authorityInstance, loginHint, account) {
|
|
12400
|
-
this.logger.trace("BrowserCacheManager.updateCacheEntries called");
|
|
12401
|
-
// Cache the request state
|
|
12402
|
-
const stateCacheKey = this.generateStateKey(state);
|
|
12403
|
-
this.setTemporaryCache(stateCacheKey, state, false);
|
|
12404
|
-
// Cache the nonce
|
|
12405
|
-
const nonceCacheKey = this.generateNonceKey(state);
|
|
12406
|
-
this.setTemporaryCache(nonceCacheKey, nonce, false);
|
|
12407
|
-
// Cache authorityKey
|
|
12408
|
-
const authorityCacheKey = this.generateAuthorityKey(state);
|
|
12409
|
-
this.setTemporaryCache(authorityCacheKey, authorityInstance, false);
|
|
12410
|
-
if (account) {
|
|
12411
|
-
const ccsCredential = {
|
|
12412
|
-
credential: account.homeAccountId,
|
|
12413
|
-
type: CcsCredentialType.HOME_ACCOUNT_ID,
|
|
12414
|
-
};
|
|
12415
|
-
this.setTemporaryCache(TemporaryCacheKeys.CCS_CREDENTIAL, JSON.stringify(ccsCredential), true);
|
|
12416
|
-
}
|
|
12417
|
-
else if (loginHint) {
|
|
12418
|
-
const ccsCredential = {
|
|
12419
|
-
credential: loginHint,
|
|
12420
|
-
type: CcsCredentialType.UPN,
|
|
12421
|
-
};
|
|
12422
|
-
this.setTemporaryCache(TemporaryCacheKeys.CCS_CREDENTIAL, JSON.stringify(ccsCredential), true);
|
|
12423
|
-
}
|
|
12424
|
-
}
|
|
12425
12399
|
/**
|
|
12426
12400
|
* Reset all temporary cache items
|
|
12427
12401
|
* @param state
|
|
12428
12402
|
*/
|
|
12429
|
-
resetRequestCache(
|
|
12403
|
+
resetRequestCache() {
|
|
12430
12404
|
this.logger.trace("BrowserCacheManager.resetRequestCache called");
|
|
12431
|
-
// check state and remove associated cache items
|
|
12432
|
-
if (state) {
|
|
12433
|
-
this.temporaryCacheStorage.getKeys().forEach((key) => {
|
|
12434
|
-
if (key.indexOf(state) !== -1) {
|
|
12435
|
-
this.removeTemporaryItem(key);
|
|
12436
|
-
}
|
|
12437
|
-
});
|
|
12438
|
-
// delete generic interactive request parameters
|
|
12439
|
-
this.removeTemporaryItem(this.generateStateKey(state));
|
|
12440
|
-
this.removeTemporaryItem(this.generateNonceKey(state));
|
|
12441
|
-
this.removeTemporaryItem(this.generateAuthorityKey(state));
|
|
12442
|
-
}
|
|
12443
12405
|
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.REQUEST_PARAMS));
|
|
12406
|
+
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.VERIFIER));
|
|
12444
12407
|
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.ORIGIN_URI));
|
|
12445
12408
|
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.URL_HASH));
|
|
12446
|
-
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.CORRELATION_ID));
|
|
12447
|
-
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.CCS_CREDENTIAL));
|
|
12448
12409
|
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST));
|
|
12449
12410
|
this.setInteractionInProgress(false);
|
|
12450
12411
|
}
|
|
12451
|
-
|
|
12452
|
-
|
|
12453
|
-
* @param stateString
|
|
12454
|
-
*/
|
|
12455
|
-
cleanRequestByState(stateString) {
|
|
12456
|
-
this.logger.trace("BrowserCacheManager.cleanRequestByState called");
|
|
12457
|
-
// Interaction is completed - remove interaction status.
|
|
12458
|
-
if (stateString) {
|
|
12459
|
-
const stateKey = this.generateStateKey(stateString);
|
|
12460
|
-
const cachedState = this.temporaryCacheStorage.getItem(stateKey);
|
|
12461
|
-
this.logger.infoPii(`BrowserCacheManager.cleanRequestByState: Removing temporary cache items for state: ${cachedState}`);
|
|
12462
|
-
this.resetRequestCache(cachedState || Constants.EMPTY_STRING);
|
|
12463
|
-
}
|
|
12464
|
-
}
|
|
12465
|
-
/**
|
|
12466
|
-
* Looks in temporary cache for any state values with the provided interactionType and removes all temporary cache items for that state
|
|
12467
|
-
* Used in scenarios where temp cache needs to be cleaned but state is not known, such as clicking browser back button.
|
|
12468
|
-
* @param interactionType
|
|
12469
|
-
*/
|
|
12470
|
-
cleanRequestByInteractionType(interactionType) {
|
|
12471
|
-
this.logger.trace("BrowserCacheManager.cleanRequestByInteractionType called");
|
|
12472
|
-
// Loop through all keys to find state key
|
|
12473
|
-
this.temporaryCacheStorage.getKeys().forEach((key) => {
|
|
12474
|
-
// If this key is not the state key, move on
|
|
12475
|
-
if (key.indexOf(TemporaryCacheKeys.REQUEST_STATE) === -1) {
|
|
12476
|
-
return;
|
|
12477
|
-
}
|
|
12478
|
-
// Retrieve state value, return if not a valid value
|
|
12479
|
-
const stateValue = this.temporaryCacheStorage.getItem(key);
|
|
12480
|
-
if (!stateValue) {
|
|
12481
|
-
return;
|
|
12482
|
-
}
|
|
12483
|
-
// Extract state and ensure it matches given InteractionType, then clean request cache
|
|
12484
|
-
const parsedState = extractBrowserRequestState(this.cryptoImpl, stateValue);
|
|
12485
|
-
if (parsedState &&
|
|
12486
|
-
parsedState.interactionType === interactionType) {
|
|
12487
|
-
this.logger.infoPii(`BrowserCacheManager.cleanRequestByInteractionType: Removing temporary cache items for state: ${stateValue}`);
|
|
12488
|
-
this.resetRequestCache(stateValue);
|
|
12489
|
-
}
|
|
12490
|
-
});
|
|
12491
|
-
this.setInteractionInProgress(false);
|
|
12492
|
-
}
|
|
12493
|
-
cacheCodeRequest(authCodeRequest) {
|
|
12494
|
-
this.logger.trace("BrowserCacheManager.cacheCodeRequest called");
|
|
12412
|
+
cacheAuthorizeRequest(authCodeRequest, codeVerifier) {
|
|
12413
|
+
this.logger.trace("BrowserCacheManager.cacheAuthorizeRequest called");
|
|
12495
12414
|
const encodedValue = base64Encode(JSON.stringify(authCodeRequest));
|
|
12496
12415
|
this.setTemporaryCache(TemporaryCacheKeys.REQUEST_PARAMS, encodedValue, true);
|
|
12416
|
+
if (codeVerifier) {
|
|
12417
|
+
const encodedVerifier = base64Encode(codeVerifier);
|
|
12418
|
+
this.setTemporaryCache(TemporaryCacheKeys.VERIFIER, encodedVerifier, true);
|
|
12419
|
+
}
|
|
12497
12420
|
}
|
|
12498
12421
|
/**
|
|
12499
12422
|
* Gets the token exchange parameters from the cache. Throws an error if nothing is found.
|
|
12500
12423
|
*/
|
|
12501
|
-
getCachedRequest(
|
|
12424
|
+
getCachedRequest() {
|
|
12502
12425
|
this.logger.trace("BrowserCacheManager.getCachedRequest called");
|
|
12503
12426
|
// Get token request from cache and parse as TokenExchangeParameters.
|
|
12504
12427
|
const encodedTokenRequest = this.getTemporaryCache(TemporaryCacheKeys.REQUEST_PARAMS, true);
|
|
12505
12428
|
if (!encodedTokenRequest) {
|
|
12506
12429
|
throw createBrowserAuthError(noTokenRequestCacheError);
|
|
12507
12430
|
}
|
|
12431
|
+
const encodedVerifier = this.getTemporaryCache(TemporaryCacheKeys.VERIFIER, true);
|
|
12508
12432
|
let parsedRequest;
|
|
12433
|
+
let verifier = "";
|
|
12509
12434
|
try {
|
|
12510
12435
|
parsedRequest = JSON.parse(base64Decode(encodedTokenRequest));
|
|
12436
|
+
if (encodedVerifier) {
|
|
12437
|
+
verifier = base64Decode(encodedVerifier);
|
|
12438
|
+
}
|
|
12511
12439
|
}
|
|
12512
12440
|
catch (e) {
|
|
12513
12441
|
this.logger.errorPii(`Attempted to parse: ${encodedTokenRequest}`);
|
|
12514
12442
|
this.logger.error(`Parsing cached token request threw with error: ${e}`);
|
|
12515
12443
|
throw createBrowserAuthError(unableToParseTokenRequestCacheError);
|
|
12516
12444
|
}
|
|
12517
|
-
|
|
12518
|
-
// Get cached authority and use if no authority is cached with request.
|
|
12519
|
-
if (!parsedRequest.authority) {
|
|
12520
|
-
const authorityCacheKey = this.generateAuthorityKey(state);
|
|
12521
|
-
const cachedAuthority = this.getTemporaryCache(authorityCacheKey);
|
|
12522
|
-
if (!cachedAuthority) {
|
|
12523
|
-
throw createBrowserAuthError(noCachedAuthorityError);
|
|
12524
|
-
}
|
|
12525
|
-
parsedRequest.authority = cachedAuthority;
|
|
12526
|
-
}
|
|
12527
|
-
return parsedRequest;
|
|
12445
|
+
return [parsedRequest, verifier];
|
|
12528
12446
|
}
|
|
12529
12447
|
/**
|
|
12530
12448
|
* Gets cached native request for redirect flows
|
|
@@ -13350,1083 +13268,1103 @@ function createNativeAuthError(code, description, ext) {
|
|
|
13350
13268
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13351
13269
|
* Licensed under the MIT License.
|
|
13352
13270
|
*/
|
|
13353
|
-
class
|
|
13271
|
+
class NativeMessageHandler {
|
|
13272
|
+
constructor(logger, handshakeTimeoutMs, performanceClient, extensionId) {
|
|
13273
|
+
this.logger = logger;
|
|
13274
|
+
this.handshakeTimeoutMs = handshakeTimeoutMs;
|
|
13275
|
+
this.extensionId = extensionId;
|
|
13276
|
+
this.resolvers = new Map(); // Used for non-handshake messages
|
|
13277
|
+
this.handshakeResolvers = new Map(); // Used for handshake messages
|
|
13278
|
+
this.messageChannel = new MessageChannel();
|
|
13279
|
+
this.windowListener = this.onWindowMessage.bind(this); // Window event callback doesn't have access to 'this' unless it's bound
|
|
13280
|
+
this.performanceClient = performanceClient;
|
|
13281
|
+
this.handshakeEvent = performanceClient.startMeasurement(PerformanceEvents.NativeMessageHandlerHandshake);
|
|
13282
|
+
}
|
|
13354
13283
|
/**
|
|
13355
|
-
*
|
|
13356
|
-
* @param
|
|
13284
|
+
* Sends a given message to the extension and resolves with the extension response
|
|
13285
|
+
* @param body
|
|
13357
13286
|
*/
|
|
13358
|
-
async
|
|
13359
|
-
this.
|
|
13360
|
-
|
|
13361
|
-
|
|
13362
|
-
|
|
13363
|
-
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
|
|
13287
|
+
async sendMessage(body) {
|
|
13288
|
+
this.logger.trace("NativeMessageHandler - sendMessage called.");
|
|
13289
|
+
const req = {
|
|
13290
|
+
channel: NativeConstants.CHANNEL_ID,
|
|
13291
|
+
extensionId: this.extensionId,
|
|
13292
|
+
responseId: createNewGuid(),
|
|
13293
|
+
body: body,
|
|
13294
|
+
};
|
|
13295
|
+
this.logger.trace("NativeMessageHandler - Sending request to browser extension");
|
|
13296
|
+
this.logger.tracePii(`NativeMessageHandler - Sending request to browser extension: ${JSON.stringify(req)}`);
|
|
13297
|
+
this.messageChannel.port1.postMessage(req);
|
|
13298
|
+
return new Promise((resolve, reject) => {
|
|
13299
|
+
this.resolvers.set(req.responseId, { resolve, reject });
|
|
13367
13300
|
});
|
|
13368
|
-
|
|
13369
|
-
|
|
13301
|
+
}
|
|
13302
|
+
/**
|
|
13303
|
+
* Returns an instance of the MessageHandler that has successfully established a connection with an extension
|
|
13304
|
+
* @param {Logger} logger
|
|
13305
|
+
* @param {number} handshakeTimeoutMs
|
|
13306
|
+
* @param {IPerformanceClient} performanceClient
|
|
13307
|
+
* @param {ICrypto} crypto
|
|
13308
|
+
*/
|
|
13309
|
+
static async createProvider(logger, handshakeTimeoutMs, performanceClient) {
|
|
13310
|
+
logger.trace("NativeMessageHandler - createProvider called.");
|
|
13370
13311
|
try {
|
|
13371
|
-
const
|
|
13372
|
-
|
|
13373
|
-
|
|
13374
|
-
fromCache: true,
|
|
13375
|
-
}, silentRequest.correlationId);
|
|
13376
|
-
return authResponse;
|
|
13312
|
+
const preferredProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient, NativeConstants.PREFERRED_EXTENSION_ID);
|
|
13313
|
+
await preferredProvider.sendHandshakeRequest();
|
|
13314
|
+
return preferredProvider;
|
|
13377
13315
|
}
|
|
13378
|
-
catch (
|
|
13379
|
-
|
|
13380
|
-
|
|
13381
|
-
|
|
13382
|
-
|
|
13383
|
-
throw error;
|
|
13316
|
+
catch (e) {
|
|
13317
|
+
// If preferred extension fails for whatever reason, fallback to using any installed extension
|
|
13318
|
+
const backupProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient);
|
|
13319
|
+
await backupProvider.sendHandshakeRequest();
|
|
13320
|
+
return backupProvider;
|
|
13384
13321
|
}
|
|
13385
13322
|
}
|
|
13386
13323
|
/**
|
|
13387
|
-
*
|
|
13388
|
-
* @param logoutRequest
|
|
13324
|
+
* Send handshake request helper.
|
|
13389
13325
|
*/
|
|
13390
|
-
|
|
13391
|
-
this.logger.
|
|
13392
|
-
|
|
13393
|
-
|
|
13394
|
-
|
|
13395
|
-
|
|
13396
|
-
|
|
13397
|
-
|
|
13398
|
-
|
|
13399
|
-
|
|
13400
|
-
|
|
13401
|
-
|
|
13402
|
-
|
|
13403
|
-
|
|
13404
|
-
|
|
13405
|
-
this.accountId = accountId;
|
|
13406
|
-
this.nativeMessageHandler = provider;
|
|
13407
|
-
this.nativeStorageManager = nativeStorageImpl;
|
|
13408
|
-
this.silentCacheClient = new SilentCacheClient(config, this.nativeStorageManager, browserCrypto, logger, eventHandler, navigationClient, performanceClient, provider, correlationId);
|
|
13409
|
-
const extensionName = this.nativeMessageHandler.getExtensionId() ===
|
|
13410
|
-
NativeConstants.PREFERRED_EXTENSION_ID
|
|
13411
|
-
? "chrome"
|
|
13412
|
-
: this.nativeMessageHandler.getExtensionId()?.length
|
|
13413
|
-
? "unknown"
|
|
13414
|
-
: undefined;
|
|
13415
|
-
this.skus = ServerTelemetryManager.makeExtraSkuString({
|
|
13416
|
-
libraryName: BrowserConstants.MSAL_SKU,
|
|
13417
|
-
libraryVersion: version,
|
|
13418
|
-
extensionName: extensionName,
|
|
13419
|
-
extensionVersion: this.nativeMessageHandler.getExtensionVersion(),
|
|
13326
|
+
async sendHandshakeRequest() {
|
|
13327
|
+
this.logger.trace("NativeMessageHandler - sendHandshakeRequest called.");
|
|
13328
|
+
// Register this event listener before sending handshake
|
|
13329
|
+
window.addEventListener("message", this.windowListener, false); // false is important, because content script message processing should work first
|
|
13330
|
+
const req = {
|
|
13331
|
+
channel: NativeConstants.CHANNEL_ID,
|
|
13332
|
+
extensionId: this.extensionId,
|
|
13333
|
+
responseId: createNewGuid(),
|
|
13334
|
+
body: {
|
|
13335
|
+
method: NativeExtensionMethod.HandshakeRequest,
|
|
13336
|
+
},
|
|
13337
|
+
};
|
|
13338
|
+
this.handshakeEvent.add({
|
|
13339
|
+
extensionId: this.extensionId,
|
|
13340
|
+
extensionHandshakeTimeoutMs: this.handshakeTimeoutMs,
|
|
13420
13341
|
});
|
|
13421
|
-
|
|
13422
|
-
|
|
13423
|
-
* Adds SKUs to request extra query parameters
|
|
13424
|
-
* @param request {NativeTokenRequest}
|
|
13425
|
-
* @private
|
|
13426
|
-
*/
|
|
13427
|
-
addRequestSKUs(request) {
|
|
13428
|
-
request.extraParameters = {
|
|
13429
|
-
...request.extraParameters,
|
|
13430
|
-
[X_CLIENT_EXTRA_SKU]: this.skus,
|
|
13342
|
+
this.messageChannel.port1.onmessage = (event) => {
|
|
13343
|
+
this.onChannelMessage(event);
|
|
13431
13344
|
};
|
|
13432
|
-
|
|
13433
|
-
|
|
13434
|
-
|
|
13435
|
-
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
|
|
13441
|
-
|
|
13442
|
-
|
|
13443
|
-
|
|
13444
|
-
|
|
13445
|
-
// initialize native request
|
|
13446
|
-
const nativeRequest = await this.initializeNativeRequest(request);
|
|
13447
|
-
// check if the tokens can be retrieved from internal cache
|
|
13448
|
-
try {
|
|
13449
|
-
const result = await this.acquireTokensFromCache(this.accountId, nativeRequest);
|
|
13450
|
-
nativeATMeasurement.end({
|
|
13451
|
-
success: true,
|
|
13452
|
-
isNativeBroker: false,
|
|
13453
|
-
fromCache: true,
|
|
13454
|
-
});
|
|
13455
|
-
return result;
|
|
13456
|
-
}
|
|
13457
|
-
catch (e) {
|
|
13458
|
-
if (cacheLookupPolicy === CacheLookupPolicy.AccessToken) {
|
|
13459
|
-
this.logger.info("MSAL internal Cache does not contain tokens, return error as per cache policy");
|
|
13460
|
-
throw e;
|
|
13461
|
-
}
|
|
13462
|
-
// continue with a native call for any and all errors
|
|
13463
|
-
this.logger.info("MSAL internal Cache does not contain tokens, proceed to make a native call");
|
|
13464
|
-
}
|
|
13465
|
-
const { ...nativeTokenRequest } = nativeRequest;
|
|
13466
|
-
// fall back to native calls
|
|
13467
|
-
const messageBody = {
|
|
13468
|
-
method: NativeExtensionMethod.GetToken,
|
|
13469
|
-
request: nativeTokenRequest,
|
|
13470
|
-
};
|
|
13471
|
-
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
13472
|
-
const validatedResponse = this.validateNativeResponse(response);
|
|
13473
|
-
return await this.handleNativeResponse(validatedResponse, nativeRequest, reqTimestamp)
|
|
13474
|
-
.then((result) => {
|
|
13475
|
-
nativeATMeasurement.end({
|
|
13476
|
-
success: true,
|
|
13477
|
-
isNativeBroker: true,
|
|
13478
|
-
requestId: result.requestId,
|
|
13479
|
-
});
|
|
13480
|
-
serverTelemetryManager.clearNativeBrokerErrorCode();
|
|
13481
|
-
return result;
|
|
13482
|
-
})
|
|
13483
|
-
.catch((error) => {
|
|
13484
|
-
nativeATMeasurement.end({
|
|
13345
|
+
window.postMessage(req, window.origin, [this.messageChannel.port2]);
|
|
13346
|
+
return new Promise((resolve, reject) => {
|
|
13347
|
+
this.handshakeResolvers.set(req.responseId, { resolve, reject });
|
|
13348
|
+
this.timeoutId = window.setTimeout(() => {
|
|
13349
|
+
/*
|
|
13350
|
+
* Throw an error if neither HandshakeResponse nor original Handshake request are received in a reasonable timeframe.
|
|
13351
|
+
* This typically suggests an event handler stopped propagation of the Handshake request but did not respond to it on the MessageChannel port
|
|
13352
|
+
*/
|
|
13353
|
+
window.removeEventListener("message", this.windowListener, false);
|
|
13354
|
+
this.messageChannel.port1.close();
|
|
13355
|
+
this.messageChannel.port2.close();
|
|
13356
|
+
this.handshakeEvent.end({
|
|
13357
|
+
extensionHandshakeTimedOut: true,
|
|
13485
13358
|
success: false,
|
|
13486
|
-
errorCode: error.errorCode,
|
|
13487
|
-
subErrorCode: error.subError,
|
|
13488
|
-
isNativeBroker: true,
|
|
13489
13359
|
});
|
|
13490
|
-
|
|
13491
|
-
|
|
13492
|
-
|
|
13493
|
-
|
|
13494
|
-
if (e instanceof NativeAuthError) {
|
|
13495
|
-
serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode);
|
|
13496
|
-
}
|
|
13497
|
-
throw e;
|
|
13498
|
-
}
|
|
13499
|
-
}
|
|
13500
|
-
/**
|
|
13501
|
-
* Creates silent flow request
|
|
13502
|
-
* @param request
|
|
13503
|
-
* @param cachedAccount
|
|
13504
|
-
* @returns CommonSilentFlowRequest
|
|
13505
|
-
*/
|
|
13506
|
-
createSilentCacheRequest(request, cachedAccount) {
|
|
13507
|
-
return {
|
|
13508
|
-
authority: request.authority,
|
|
13509
|
-
correlationId: this.correlationId,
|
|
13510
|
-
scopes: ScopeSet.fromString(request.scope).asArray(),
|
|
13511
|
-
account: cachedAccount,
|
|
13512
|
-
forceRefresh: false,
|
|
13513
|
-
};
|
|
13360
|
+
reject(createBrowserAuthError(nativeHandshakeTimeout));
|
|
13361
|
+
this.handshakeResolvers.delete(req.responseId);
|
|
13362
|
+
}, this.handshakeTimeoutMs); // Use a reasonable timeout in milliseconds here
|
|
13363
|
+
});
|
|
13514
13364
|
}
|
|
13515
13365
|
/**
|
|
13516
|
-
*
|
|
13517
|
-
* @param
|
|
13518
|
-
* @param request
|
|
13519
|
-
* @returns authenticationResult
|
|
13366
|
+
* Invoked when a message is posted to the window. If a handshake request is received it means the extension is not installed.
|
|
13367
|
+
* @param event
|
|
13520
13368
|
*/
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
|
|
13369
|
+
onWindowMessage(event) {
|
|
13370
|
+
this.logger.trace("NativeMessageHandler - onWindowMessage called");
|
|
13371
|
+
// We only accept messages from ourselves
|
|
13372
|
+
if (event.source !== window) {
|
|
13373
|
+
return;
|
|
13525
13374
|
}
|
|
13526
|
-
|
|
13527
|
-
|
|
13528
|
-
|
|
13529
|
-
|
|
13530
|
-
if (!account) {
|
|
13531
|
-
throw createClientAuthError(noAccountFound);
|
|
13375
|
+
const request = event.data;
|
|
13376
|
+
if (!request.channel ||
|
|
13377
|
+
request.channel !== NativeConstants.CHANNEL_ID) {
|
|
13378
|
+
return;
|
|
13532
13379
|
}
|
|
13533
|
-
|
|
13534
|
-
|
|
13535
|
-
const silentRequest = this.createSilentCacheRequest(request, account);
|
|
13536
|
-
const result = await this.silentCacheClient.acquireToken(silentRequest);
|
|
13537
|
-
const fullAccount = {
|
|
13538
|
-
...account,
|
|
13539
|
-
idTokenClaims: result?.idTokenClaims,
|
|
13540
|
-
idToken: result?.idToken,
|
|
13541
|
-
};
|
|
13542
|
-
return {
|
|
13543
|
-
...result,
|
|
13544
|
-
account: fullAccount,
|
|
13545
|
-
};
|
|
13380
|
+
if (request.extensionId && request.extensionId !== this.extensionId) {
|
|
13381
|
+
return;
|
|
13546
13382
|
}
|
|
13547
|
-
|
|
13548
|
-
|
|
13383
|
+
if (request.body.method === NativeExtensionMethod.HandshakeRequest) {
|
|
13384
|
+
const handshakeResolver = this.handshakeResolvers.get(request.responseId);
|
|
13385
|
+
/*
|
|
13386
|
+
* Filter out responses with no matched resolvers sooner to keep channel ports open while waiting for
|
|
13387
|
+
* the proper response.
|
|
13388
|
+
*/
|
|
13389
|
+
if (!handshakeResolver) {
|
|
13390
|
+
this.logger.trace(`NativeMessageHandler.onWindowMessage - resolver can't be found for request ${request.responseId}`);
|
|
13391
|
+
return;
|
|
13392
|
+
}
|
|
13393
|
+
// If we receive this message back it means no extension intercepted the request, meaning no extension supporting handshake protocol is installed
|
|
13394
|
+
this.logger.verbose(request.extensionId
|
|
13395
|
+
? `Extension with id: ${request.extensionId} not installed`
|
|
13396
|
+
: "No extension installed");
|
|
13397
|
+
clearTimeout(this.timeoutId);
|
|
13398
|
+
this.messageChannel.port1.close();
|
|
13399
|
+
this.messageChannel.port2.close();
|
|
13400
|
+
window.removeEventListener("message", this.windowListener, false);
|
|
13401
|
+
this.handshakeEvent.end({
|
|
13402
|
+
success: false,
|
|
13403
|
+
extensionInstalled: false,
|
|
13404
|
+
});
|
|
13405
|
+
handshakeResolver.reject(createBrowserAuthError(nativeExtensionNotInstalled));
|
|
13549
13406
|
}
|
|
13550
13407
|
}
|
|
13551
13408
|
/**
|
|
13552
|
-
*
|
|
13553
|
-
* @param
|
|
13554
|
-
* @param {InProgressPerformanceEvent} rootMeasurement
|
|
13409
|
+
* Invoked when a message is received from the extension on the MessageChannel port
|
|
13410
|
+
* @param event
|
|
13555
13411
|
*/
|
|
13556
|
-
|
|
13557
|
-
this.logger.trace("
|
|
13558
|
-
const
|
|
13559
|
-
|
|
13560
|
-
const
|
|
13561
|
-
const messageBody = {
|
|
13562
|
-
method: NativeExtensionMethod.GetToken,
|
|
13563
|
-
request: nativeRequest,
|
|
13564
|
-
};
|
|
13412
|
+
onChannelMessage(event) {
|
|
13413
|
+
this.logger.trace("NativeMessageHandler - onChannelMessage called.");
|
|
13414
|
+
const request = event.data;
|
|
13415
|
+
const resolver = this.resolvers.get(request.responseId);
|
|
13416
|
+
const handshakeResolver = this.handshakeResolvers.get(request.responseId);
|
|
13565
13417
|
try {
|
|
13566
|
-
const
|
|
13567
|
-
|
|
13568
|
-
|
|
13569
|
-
|
|
13570
|
-
|
|
13571
|
-
|
|
13572
|
-
|
|
13573
|
-
|
|
13574
|
-
if (
|
|
13575
|
-
|
|
13418
|
+
const method = request.body.method;
|
|
13419
|
+
if (method === NativeExtensionMethod.Response) {
|
|
13420
|
+
if (!resolver) {
|
|
13421
|
+
return;
|
|
13422
|
+
}
|
|
13423
|
+
const response = request.body.response;
|
|
13424
|
+
this.logger.trace("NativeMessageHandler - Received response from browser extension");
|
|
13425
|
+
this.logger.tracePii(`NativeMessageHandler - Received response from browser extension: ${JSON.stringify(response)}`);
|
|
13426
|
+
if (response.status !== "Success") {
|
|
13427
|
+
resolver.reject(createNativeAuthError(response.code, response.description, response.ext));
|
|
13428
|
+
}
|
|
13429
|
+
else if (response.result) {
|
|
13430
|
+
if (response.result["code"] &&
|
|
13431
|
+
response.result["description"]) {
|
|
13432
|
+
resolver.reject(createNativeAuthError(response.result["code"], response.result["description"], response.result["ext"]));
|
|
13433
|
+
}
|
|
13434
|
+
else {
|
|
13435
|
+
resolver.resolve(response.result);
|
|
13436
|
+
}
|
|
13437
|
+
}
|
|
13438
|
+
else {
|
|
13439
|
+
throw createAuthError(unexpectedError, "Event does not contain result.");
|
|
13576
13440
|
}
|
|
13441
|
+
this.resolvers.delete(request.responseId);
|
|
13442
|
+
}
|
|
13443
|
+
else if (method === NativeExtensionMethod.HandshakeResponse) {
|
|
13444
|
+
if (!handshakeResolver) {
|
|
13445
|
+
this.logger.trace(`NativeMessageHandler.onChannelMessage - resolver can't be found for request ${request.responseId}`);
|
|
13446
|
+
return;
|
|
13447
|
+
}
|
|
13448
|
+
clearTimeout(this.timeoutId); // Clear setTimeout
|
|
13449
|
+
window.removeEventListener("message", this.windowListener, false); // Remove 'No extension' listener
|
|
13450
|
+
this.extensionId = request.extensionId;
|
|
13451
|
+
this.extensionVersion = request.body.version;
|
|
13452
|
+
this.logger.verbose(`NativeMessageHandler - Received HandshakeResponse from extension: ${this.extensionId}`);
|
|
13453
|
+
this.handshakeEvent.end({
|
|
13454
|
+
extensionInstalled: true,
|
|
13455
|
+
success: true,
|
|
13456
|
+
});
|
|
13457
|
+
handshakeResolver.resolve();
|
|
13458
|
+
this.handshakeResolvers.delete(request.responseId);
|
|
13459
|
+
}
|
|
13460
|
+
// Do nothing if method is not Response or HandshakeResponse
|
|
13461
|
+
}
|
|
13462
|
+
catch (err) {
|
|
13463
|
+
this.logger.error("Error parsing response from WAM Extension");
|
|
13464
|
+
this.logger.errorPii(`Error parsing response from WAM Extension: ${err}`);
|
|
13465
|
+
this.logger.errorPii(`Unable to parse ${event}`);
|
|
13466
|
+
if (resolver) {
|
|
13467
|
+
resolver.reject(err);
|
|
13468
|
+
}
|
|
13469
|
+
else if (handshakeResolver) {
|
|
13470
|
+
handshakeResolver.reject(err);
|
|
13577
13471
|
}
|
|
13578
13472
|
}
|
|
13579
|
-
this.browserStorage.setTemporaryCache(TemporaryCacheKeys.NATIVE_REQUEST, JSON.stringify(nativeRequest), true);
|
|
13580
|
-
const navigationOptions = {
|
|
13581
|
-
apiId: ApiId.acquireTokenRedirect,
|
|
13582
|
-
timeout: this.config.system.redirectNavigationTimeout,
|
|
13583
|
-
noHistory: false,
|
|
13584
|
-
};
|
|
13585
|
-
const redirectUri = this.config.auth.navigateToLoginRequestUrl
|
|
13586
|
-
? window.location.href
|
|
13587
|
-
: this.getRedirectUri(request.redirectUri);
|
|
13588
|
-
rootMeasurement.end({ success: true });
|
|
13589
|
-
await this.navigationClient.navigateExternal(redirectUri, navigationOptions); // Need to treat this as external to ensure handleRedirectPromise is run again
|
|
13590
13473
|
}
|
|
13591
13474
|
/**
|
|
13592
|
-
*
|
|
13593
|
-
* @
|
|
13594
|
-
* @param correlationId {string?} correlation identifier
|
|
13475
|
+
* Returns the Id for the browser extension this handler is communicating with
|
|
13476
|
+
* @returns
|
|
13595
13477
|
*/
|
|
13596
|
-
|
|
13597
|
-
this.
|
|
13598
|
-
if (!this.browserStorage.isInteractionInProgress(true)) {
|
|
13599
|
-
this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
|
|
13600
|
-
return null;
|
|
13601
|
-
}
|
|
13602
|
-
// remove prompt from the request to prevent WAM from prompting twice
|
|
13603
|
-
const cachedRequest = this.browserStorage.getCachedNativeRequest();
|
|
13604
|
-
if (!cachedRequest) {
|
|
13605
|
-
this.logger.verbose("NativeInteractionClient - handleRedirectPromise called but there is no cached request, returning null.");
|
|
13606
|
-
if (performanceClient && correlationId) {
|
|
13607
|
-
performanceClient?.addFields({ errorCode: "no_cached_request" }, correlationId);
|
|
13608
|
-
}
|
|
13609
|
-
return null;
|
|
13610
|
-
}
|
|
13611
|
-
const { prompt, ...request } = cachedRequest;
|
|
13612
|
-
if (prompt) {
|
|
13613
|
-
this.logger.verbose("NativeInteractionClient - handleRedirectPromise called and prompt was included in the original request, removing prompt from cached request to prevent second interaction with native broker window.");
|
|
13614
|
-
}
|
|
13615
|
-
this.browserStorage.removeItem(this.browserStorage.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST));
|
|
13616
|
-
const messageBody = {
|
|
13617
|
-
method: NativeExtensionMethod.GetToken,
|
|
13618
|
-
request: request,
|
|
13619
|
-
};
|
|
13620
|
-
const reqTimestamp = nowSeconds();
|
|
13621
|
-
try {
|
|
13622
|
-
this.logger.verbose("NativeInteractionClient - handleRedirectPromise sending message to native broker.");
|
|
13623
|
-
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
13624
|
-
this.validateNativeResponse(response);
|
|
13625
|
-
const result = this.handleNativeResponse(response, request, reqTimestamp);
|
|
13626
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
13627
|
-
const res = await result;
|
|
13628
|
-
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
13629
|
-
serverTelemetryManager.clearNativeBrokerErrorCode();
|
|
13630
|
-
return res;
|
|
13631
|
-
}
|
|
13632
|
-
catch (e) {
|
|
13633
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
13634
|
-
throw e;
|
|
13635
|
-
}
|
|
13478
|
+
getExtensionId() {
|
|
13479
|
+
return this.extensionId;
|
|
13636
13480
|
}
|
|
13637
13481
|
/**
|
|
13638
|
-
*
|
|
13639
|
-
* @
|
|
13482
|
+
* Returns the version for the browser extension this handler is communicating with
|
|
13483
|
+
* @returns
|
|
13640
13484
|
*/
|
|
13641
|
-
|
|
13642
|
-
this.
|
|
13643
|
-
return Promise.reject("Logout not implemented yet");
|
|
13485
|
+
getExtensionVersion() {
|
|
13486
|
+
return this.extensionVersion;
|
|
13644
13487
|
}
|
|
13645
13488
|
/**
|
|
13646
|
-
*
|
|
13647
|
-
* @param
|
|
13648
|
-
* @param
|
|
13649
|
-
* @param
|
|
13489
|
+
* Returns boolean indicating whether or not the request should attempt to use native broker
|
|
13490
|
+
* @param logger
|
|
13491
|
+
* @param config
|
|
13492
|
+
* @param nativeExtensionProvider
|
|
13493
|
+
* @param authenticationScheme
|
|
13650
13494
|
*/
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
nativeAccountId: request.accountId,
|
|
13658
|
-
})?.homeAccountId;
|
|
13659
|
-
// add exception for double brokering, please note this is temporary and will be fortified in future
|
|
13660
|
-
if (request.extraParameters?.child_client_id &&
|
|
13661
|
-
response.account.id !== request.accountId) {
|
|
13662
|
-
this.logger.info("handleNativeServerResponse: Double broker flow detected, ignoring accountId mismatch");
|
|
13495
|
+
static isPlatformBrokerAvailable(config, logger, nativeExtensionProvider, authenticationScheme) {
|
|
13496
|
+
logger.trace("isPlatformBrokerAvailable called");
|
|
13497
|
+
if (!config.system.allowPlatformBroker) {
|
|
13498
|
+
logger.trace("isPlatformBrokerAvailable: allowPlatformBroker is not enabled, returning false");
|
|
13499
|
+
// Developer disabled WAM
|
|
13500
|
+
return false;
|
|
13663
13501
|
}
|
|
13664
|
-
|
|
13665
|
-
|
|
13666
|
-
//
|
|
13667
|
-
|
|
13502
|
+
if (!nativeExtensionProvider) {
|
|
13503
|
+
logger.trace("isPlatformBrokerAvailable: Platform extension provider is not initialized, returning false");
|
|
13504
|
+
// Extension is not available
|
|
13505
|
+
return false;
|
|
13668
13506
|
}
|
|
13669
|
-
|
|
13670
|
-
|
|
13671
|
-
|
|
13672
|
-
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
await this.cacheAccount(baseAccount);
|
|
13682
|
-
await this.cacheNativeTokens(response, request, homeAccountIdentifier, idTokenClaims, response.access_token, result.tenantId, reqTimestamp);
|
|
13683
|
-
return result;
|
|
13507
|
+
if (authenticationScheme) {
|
|
13508
|
+
switch (authenticationScheme) {
|
|
13509
|
+
case AuthenticationScheme.BEARER:
|
|
13510
|
+
case AuthenticationScheme.POP:
|
|
13511
|
+
logger.trace("isPlatformBrokerAvailable: authenticationScheme is supported, returning true");
|
|
13512
|
+
return true;
|
|
13513
|
+
default:
|
|
13514
|
+
logger.trace("isPlatformBrokerAvailable: authenticationScheme is not supported, returning false");
|
|
13515
|
+
return false;
|
|
13516
|
+
}
|
|
13517
|
+
}
|
|
13518
|
+
return true;
|
|
13684
13519
|
}
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13694
|
-
|
|
13520
|
+
}
|
|
13521
|
+
|
|
13522
|
+
/*
|
|
13523
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13524
|
+
* Licensed under the MIT License.
|
|
13525
|
+
*/
|
|
13526
|
+
/**
|
|
13527
|
+
* Extracts the BrowserStateObject from the state string.
|
|
13528
|
+
* @param browserCrypto
|
|
13529
|
+
* @param state
|
|
13530
|
+
*/
|
|
13531
|
+
function extractBrowserRequestState(browserCrypto, state) {
|
|
13532
|
+
if (!state) {
|
|
13533
|
+
return null;
|
|
13695
13534
|
}
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13705
|
-
|
|
13535
|
+
try {
|
|
13536
|
+
const requestStateObj = ProtocolUtils.parseRequestState(browserCrypto, state);
|
|
13537
|
+
return requestStateObj.libraryState.meta;
|
|
13538
|
+
}
|
|
13539
|
+
catch (e) {
|
|
13540
|
+
throw createClientAuthError(invalidState);
|
|
13541
|
+
}
|
|
13542
|
+
}
|
|
13543
|
+
|
|
13544
|
+
/*
|
|
13545
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13546
|
+
* Licensed under the MIT License.
|
|
13547
|
+
*/
|
|
13548
|
+
function deserializeResponse(responseString, responseLocation, logger) {
|
|
13549
|
+
// Deserialize hash fragment response parameters.
|
|
13550
|
+
const serverParams = getDeserializedResponse(responseString);
|
|
13551
|
+
if (!serverParams) {
|
|
13552
|
+
if (!stripLeadingHashOrQuery(responseString)) {
|
|
13553
|
+
// Hash or Query string is empty
|
|
13554
|
+
logger.error(`The request has returned to the redirectUri but a ${responseLocation} is not present. It's likely that the ${responseLocation} has been removed or the page has been redirected by code running on the redirectUri page.`);
|
|
13555
|
+
throw createBrowserAuthError(hashEmptyError);
|
|
13556
|
+
}
|
|
13557
|
+
else {
|
|
13558
|
+
logger.error(`A ${responseLocation} is present in the iframe but it does not contain known properties. It's likely that the ${responseLocation} has been replaced by code running on the redirectUri page.`);
|
|
13559
|
+
logger.errorPii(`The ${responseLocation} detected is: ${responseString}`);
|
|
13560
|
+
throw createBrowserAuthError(hashDoesNotContainKnownProperties);
|
|
13561
|
+
}
|
|
13562
|
+
}
|
|
13563
|
+
return serverParams;
|
|
13564
|
+
}
|
|
13565
|
+
/**
|
|
13566
|
+
* Returns the interaction type that the response object belongs to
|
|
13567
|
+
*/
|
|
13568
|
+
function validateInteractionType(response, browserCrypto, interactionType) {
|
|
13569
|
+
if (!response.state) {
|
|
13570
|
+
throw createBrowserAuthError(noStateInHash);
|
|
13571
|
+
}
|
|
13572
|
+
const platformStateObj = extractBrowserRequestState(browserCrypto, response.state);
|
|
13573
|
+
if (!platformStateObj) {
|
|
13574
|
+
throw createBrowserAuthError(unableToParseState);
|
|
13575
|
+
}
|
|
13576
|
+
if (platformStateObj.interactionType !== interactionType) {
|
|
13577
|
+
throw createBrowserAuthError(stateInteractionTypeMismatch);
|
|
13578
|
+
}
|
|
13579
|
+
}
|
|
13580
|
+
|
|
13581
|
+
/*
|
|
13582
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13583
|
+
* Licensed under the MIT License.
|
|
13584
|
+
*/
|
|
13585
|
+
/**
|
|
13586
|
+
* Abstract class which defines operations for a browser interaction handling class.
|
|
13587
|
+
*/
|
|
13588
|
+
class InteractionHandler {
|
|
13589
|
+
constructor(authCodeModule, storageImpl, authCodeRequest, logger, performanceClient) {
|
|
13590
|
+
this.authModule = authCodeModule;
|
|
13591
|
+
this.browserStorage = storageImpl;
|
|
13592
|
+
this.authCodeRequest = authCodeRequest;
|
|
13593
|
+
this.logger = logger;
|
|
13594
|
+
this.performanceClient = performanceClient;
|
|
13706
13595
|
}
|
|
13707
13596
|
/**
|
|
13708
|
-
*
|
|
13709
|
-
* @param
|
|
13710
|
-
* @param response
|
|
13597
|
+
* Function to handle response parameters from hash.
|
|
13598
|
+
* @param locationHash
|
|
13711
13599
|
*/
|
|
13712
|
-
async
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13600
|
+
async handleCodeResponse(response, request) {
|
|
13601
|
+
this.performanceClient.addQueueMeasurement(PerformanceEvents.HandleCodeResponse, request.correlationId);
|
|
13602
|
+
let authCodeResponse;
|
|
13603
|
+
try {
|
|
13604
|
+
authCodeResponse = getAuthorizationCodePayload(response, request.state);
|
|
13605
|
+
}
|
|
13606
|
+
catch (e) {
|
|
13607
|
+
if (e instanceof ServerError &&
|
|
13608
|
+
e.subError === userCancelled) {
|
|
13609
|
+
// Translate server error caused by user closing native prompt to corresponding first class MSAL error
|
|
13610
|
+
throw createBrowserAuthError(userCancelled);
|
|
13723
13611
|
}
|
|
13724
|
-
|
|
13725
|
-
|
|
13726
|
-
const shrParameters = {
|
|
13727
|
-
resourceRequestMethod: request.resourceRequestMethod,
|
|
13728
|
-
resourceRequestUri: request.resourceRequestUri,
|
|
13729
|
-
shrClaims: request.shrClaims,
|
|
13730
|
-
shrNonce: request.shrNonce,
|
|
13731
|
-
};
|
|
13732
|
-
/**
|
|
13733
|
-
* KeyID must be present in the native request from when the PoP key was generated in order for
|
|
13734
|
-
* PopTokenGenerator to query the full key for signing
|
|
13735
|
-
*/
|
|
13736
|
-
if (!request.keyId) {
|
|
13737
|
-
throw createClientAuthError(keyIdMissing);
|
|
13612
|
+
else {
|
|
13613
|
+
throw e;
|
|
13738
13614
|
}
|
|
13739
|
-
|
|
13615
|
+
}
|
|
13616
|
+
return invokeAsync(this.handleCodeResponseFromServer.bind(this), PerformanceEvents.HandleCodeResponseFromServer, this.logger, this.performanceClient, request.correlationId)(authCodeResponse, request);
|
|
13617
|
+
}
|
|
13618
|
+
/**
|
|
13619
|
+
* Process auth code response from AAD
|
|
13620
|
+
* @param authCodeResponse
|
|
13621
|
+
* @param state
|
|
13622
|
+
* @param authority
|
|
13623
|
+
* @param networkModule
|
|
13624
|
+
* @returns
|
|
13625
|
+
*/
|
|
13626
|
+
async handleCodeResponseFromServer(authCodeResponse, request, validateNonce = true) {
|
|
13627
|
+
this.performanceClient.addQueueMeasurement(PerformanceEvents.HandleCodeResponseFromServer, request.correlationId);
|
|
13628
|
+
this.logger.trace("InteractionHandler.handleCodeResponseFromServer called");
|
|
13629
|
+
// Assign code to request
|
|
13630
|
+
this.authCodeRequest.code = authCodeResponse.code;
|
|
13631
|
+
// Check for new cloud instance
|
|
13632
|
+
if (authCodeResponse.cloud_instance_host_name) {
|
|
13633
|
+
await invokeAsync(this.authModule.updateAuthority.bind(this.authModule), PerformanceEvents.UpdateTokenEndpointAuthority, this.logger, this.performanceClient, request.correlationId)(authCodeResponse.cloud_instance_host_name, request.correlationId);
|
|
13634
|
+
}
|
|
13635
|
+
// Nonce validation not needed when redirect not involved (e.g. hybrid spa, renewing token via rt)
|
|
13636
|
+
if (validateNonce) {
|
|
13637
|
+
// TODO: Assigning "response nonce" to "request nonce" is confusing. Refactor the function doing validation to accept request nonce directly
|
|
13638
|
+
authCodeResponse.nonce = request.nonce || undefined;
|
|
13639
|
+
}
|
|
13640
|
+
authCodeResponse.state = request.state;
|
|
13641
|
+
// Add CCS parameters if available
|
|
13642
|
+
if (authCodeResponse.client_info) {
|
|
13643
|
+
this.authCodeRequest.clientInfo = authCodeResponse.client_info;
|
|
13740
13644
|
}
|
|
13741
13645
|
else {
|
|
13742
|
-
|
|
13646
|
+
const ccsCred = this.createCcsCredentials(request);
|
|
13647
|
+
if (ccsCred) {
|
|
13648
|
+
this.authCodeRequest.ccsCredential = ccsCred;
|
|
13649
|
+
}
|
|
13743
13650
|
}
|
|
13651
|
+
// Acquire token with retrieved code.
|
|
13652
|
+
const tokenResponse = (await invokeAsync(this.authModule.acquireToken.bind(this.authModule), PerformanceEvents.AuthClientAcquireToken, this.logger, this.performanceClient, request.correlationId)(this.authCodeRequest, authCodeResponse));
|
|
13653
|
+
return tokenResponse;
|
|
13744
13654
|
}
|
|
13745
13655
|
/**
|
|
13746
|
-
*
|
|
13747
|
-
* @param response
|
|
13748
|
-
* @param request
|
|
13749
|
-
* @param idTokenObj
|
|
13750
|
-
* @param accountEntity
|
|
13751
|
-
* @param authority
|
|
13752
|
-
* @param reqTimestamp
|
|
13753
|
-
* @returns
|
|
13656
|
+
* Build ccs creds if available
|
|
13754
13657
|
*/
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
13759
|
-
|
|
13760
|
-
|
|
13761
|
-
: ScopeSet.fromString(request.scope);
|
|
13762
|
-
const accountProperties = response.account.properties || {};
|
|
13763
|
-
const uid = accountProperties["UID"] ||
|
|
13764
|
-
idTokenClaims.oid ||
|
|
13765
|
-
idTokenClaims.sub ||
|
|
13766
|
-
Constants.EMPTY_STRING;
|
|
13767
|
-
const tid = accountProperties["TenantId"] ||
|
|
13768
|
-
idTokenClaims.tid ||
|
|
13769
|
-
Constants.EMPTY_STRING;
|
|
13770
|
-
const accountInfo = updateAccountTenantProfileData(accountEntity.getAccountInfo(), undefined, // tenantProfile optional
|
|
13771
|
-
idTokenClaims, response.id_token);
|
|
13772
|
-
/**
|
|
13773
|
-
* In pairwise broker flows, this check prevents the broker's native account id
|
|
13774
|
-
* from being returned over the embedded app's account id.
|
|
13775
|
-
*/
|
|
13776
|
-
if (accountInfo.nativeAccountId !== response.account.id) {
|
|
13777
|
-
accountInfo.nativeAccountId = response.account.id;
|
|
13658
|
+
createCcsCredentials(request) {
|
|
13659
|
+
if (request.account) {
|
|
13660
|
+
return {
|
|
13661
|
+
credential: request.account.homeAccountId,
|
|
13662
|
+
type: CcsCredentialType.HOME_ACCOUNT_ID,
|
|
13663
|
+
};
|
|
13778
13664
|
}
|
|
13779
|
-
|
|
13780
|
-
|
|
13781
|
-
|
|
13782
|
-
|
|
13783
|
-
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
uniqueId: uid,
|
|
13787
|
-
tenantId: tid,
|
|
13788
|
-
scopes: responseScopes.asArray(),
|
|
13789
|
-
account: accountInfo,
|
|
13790
|
-
idToken: response.id_token,
|
|
13791
|
-
idTokenClaims: idTokenClaims,
|
|
13792
|
-
accessToken: responseAccessToken,
|
|
13793
|
-
fromCache: mats ? this.isResponseFromCache(mats) : false,
|
|
13794
|
-
// Request timestamp and NativeResponse expires_in are in seconds, converting to Date for AuthenticationResult
|
|
13795
|
-
expiresOn: toDateFromSeconds(reqTimestamp + response.expires_in),
|
|
13796
|
-
tokenType: tokenType,
|
|
13797
|
-
correlationId: this.correlationId,
|
|
13798
|
-
state: response.state,
|
|
13799
|
-
fromNativeBroker: true,
|
|
13800
|
-
};
|
|
13801
|
-
return result;
|
|
13665
|
+
else if (request.loginHint) {
|
|
13666
|
+
return {
|
|
13667
|
+
credential: request.loginHint,
|
|
13668
|
+
type: CcsCredentialType.UPN,
|
|
13669
|
+
};
|
|
13670
|
+
}
|
|
13671
|
+
return null;
|
|
13802
13672
|
}
|
|
13673
|
+
}
|
|
13674
|
+
|
|
13675
|
+
/*
|
|
13676
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13677
|
+
* Licensed under the MIT License.
|
|
13678
|
+
*/
|
|
13679
|
+
class SilentCacheClient extends StandardInteractionClient {
|
|
13803
13680
|
/**
|
|
13804
|
-
*
|
|
13805
|
-
* @param
|
|
13681
|
+
* Returns unexpired tokens from the cache, if available
|
|
13682
|
+
* @param silentRequest
|
|
13806
13683
|
*/
|
|
13807
|
-
async
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
this.
|
|
13812
|
-
|
|
13684
|
+
async acquireToken(silentRequest) {
|
|
13685
|
+
this.performanceClient.addQueueMeasurement(PerformanceEvents.SilentCacheClientAcquireToken, silentRequest.correlationId);
|
|
13686
|
+
// Telemetry manager only used to increment cacheHits here
|
|
13687
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenSilent_silentFlow);
|
|
13688
|
+
const clientConfig = await invokeAsync(this.getClientConfiguration.bind(this), PerformanceEvents.StandardInteractionClientGetClientConfiguration, this.logger, this.performanceClient, this.correlationId)({
|
|
13689
|
+
serverTelemetryManager,
|
|
13690
|
+
requestAuthority: silentRequest.authority,
|
|
13691
|
+
requestAzureCloudOptions: silentRequest.azureCloudOptions,
|
|
13692
|
+
account: silentRequest.account,
|
|
13813
13693
|
});
|
|
13694
|
+
const silentAuthClient = new SilentFlowClient(clientConfig, this.performanceClient);
|
|
13695
|
+
this.logger.verbose("Silent auth client created");
|
|
13696
|
+
try {
|
|
13697
|
+
const response = await invokeAsync(silentAuthClient.acquireCachedToken.bind(silentAuthClient), PerformanceEvents.SilentFlowClientAcquireCachedToken, this.logger, this.performanceClient, silentRequest.correlationId)(silentRequest);
|
|
13698
|
+
const authResponse = response[0];
|
|
13699
|
+
this.performanceClient.addFields({
|
|
13700
|
+
fromCache: true,
|
|
13701
|
+
}, silentRequest.correlationId);
|
|
13702
|
+
return authResponse;
|
|
13703
|
+
}
|
|
13704
|
+
catch (error) {
|
|
13705
|
+
if (error instanceof BrowserAuthError &&
|
|
13706
|
+
error.errorCode === cryptoKeyNotFound) {
|
|
13707
|
+
this.logger.verbose("Signing keypair for bound access token not found. Refreshing bound access token and generating a new crypto keypair.");
|
|
13708
|
+
}
|
|
13709
|
+
throw error;
|
|
13710
|
+
}
|
|
13814
13711
|
}
|
|
13815
13712
|
/**
|
|
13816
|
-
*
|
|
13817
|
-
* @param
|
|
13818
|
-
* @param request
|
|
13819
|
-
* @param homeAccountIdentifier
|
|
13820
|
-
* @param idTokenObj
|
|
13821
|
-
* @param responseAccessToken
|
|
13822
|
-
* @param tenantId
|
|
13823
|
-
* @param reqTimestamp
|
|
13713
|
+
* API to silenty clear the browser cache.
|
|
13714
|
+
* @param logoutRequest
|
|
13824
13715
|
*/
|
|
13825
|
-
|
|
13826
|
-
|
|
13827
|
-
|
|
13828
|
-
|
|
13829
|
-
? Constants.SHR_NONCE_VALIDITY
|
|
13830
|
-
: (typeof response.expires_in === "string"
|
|
13831
|
-
? parseInt(response.expires_in, 10)
|
|
13832
|
-
: response.expires_in) || 0;
|
|
13833
|
-
const tokenExpirationSeconds = reqTimestamp + expiresIn;
|
|
13834
|
-
const responseScopes = this.generateScopes(response, request);
|
|
13835
|
-
const cachedAccessToken = createAccessTokenEntity(homeAccountIdentifier, request.authority, responseAccessToken, request.clientId, idTokenClaims.tid || tenantId, responseScopes.printScopes(), tokenExpirationSeconds, 0, base64Decode, undefined, request.tokenType, undefined, request.keyId);
|
|
13836
|
-
const nativeCacheRecord = {
|
|
13837
|
-
idToken: cachedIdToken,
|
|
13838
|
-
accessToken: cachedAccessToken,
|
|
13839
|
-
};
|
|
13840
|
-
return this.nativeStorageManager.saveCacheRecord(nativeCacheRecord, this.correlationId, request.storeInCache);
|
|
13716
|
+
logout(logoutRequest) {
|
|
13717
|
+
this.logger.verbose("logoutRedirect called");
|
|
13718
|
+
const validLogoutRequest = this.initializeLogoutRequest(logoutRequest);
|
|
13719
|
+
return this.clearCacheOnLogout(validLogoutRequest?.account);
|
|
13841
13720
|
}
|
|
13842
|
-
|
|
13843
|
-
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13721
|
+
}
|
|
13722
|
+
|
|
13723
|
+
/*
|
|
13724
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13725
|
+
* Licensed under the MIT License.
|
|
13726
|
+
*/
|
|
13727
|
+
class NativeInteractionClient extends BaseInteractionClient {
|
|
13728
|
+
constructor(config, browserStorage, browserCrypto, logger, eventHandler, navigationClient, apiId, performanceClient, provider, accountId, nativeStorageImpl, correlationId) {
|
|
13729
|
+
super(config, browserStorage, browserCrypto, logger, eventHandler, navigationClient, performanceClient, provider, correlationId);
|
|
13730
|
+
this.apiId = apiId;
|
|
13731
|
+
this.accountId = accountId;
|
|
13732
|
+
this.nativeMessageHandler = provider;
|
|
13733
|
+
this.nativeStorageManager = nativeStorageImpl;
|
|
13734
|
+
this.silentCacheClient = new SilentCacheClient(config, this.nativeStorageManager, browserCrypto, logger, eventHandler, navigationClient, performanceClient, provider, correlationId);
|
|
13735
|
+
const extensionName = this.nativeMessageHandler.getExtensionId() ===
|
|
13736
|
+
NativeConstants.PREFERRED_EXTENSION_ID
|
|
13737
|
+
? "chrome"
|
|
13738
|
+
: this.nativeMessageHandler.getExtensionId()?.length
|
|
13739
|
+
? "unknown"
|
|
13740
|
+
: undefined;
|
|
13741
|
+
this.skus = ServerTelemetryManager.makeExtraSkuString({
|
|
13742
|
+
libraryName: BrowserConstants.MSAL_SKU,
|
|
13743
|
+
libraryVersion: version,
|
|
13744
|
+
extensionName: extensionName,
|
|
13849
13745
|
extensionVersion: this.nativeMessageHandler.getExtensionVersion(),
|
|
13850
|
-
|
|
13851
|
-
matsAccountJoinOnStart: mats.account_join_on_start,
|
|
13852
|
-
matsAccountJoinOnEnd: mats.account_join_on_end,
|
|
13853
|
-
matsDeviceJoin: mats.device_join,
|
|
13854
|
-
matsPromptBehavior: mats.prompt_behavior,
|
|
13855
|
-
matsApiErrorCode: mats.api_error_code,
|
|
13856
|
-
matsUiVisible: mats.ui_visible,
|
|
13857
|
-
matsSilentCode: mats.silent_code,
|
|
13858
|
-
matsSilentBiSubCode: mats.silent_bi_sub_code,
|
|
13859
|
-
matsSilentMessage: mats.silent_message,
|
|
13860
|
-
matsSilentStatus: mats.silent_status,
|
|
13861
|
-
matsHttpStatus: mats.http_status,
|
|
13862
|
-
matsHttpEventCount: mats.http_event_count,
|
|
13863
|
-
}, this.correlationId);
|
|
13864
|
-
return mats;
|
|
13746
|
+
});
|
|
13865
13747
|
}
|
|
13866
13748
|
/**
|
|
13867
|
-
*
|
|
13868
|
-
* @param
|
|
13749
|
+
* Adds SKUs to request extra query parameters
|
|
13750
|
+
* @param request {NativeTokenRequest}
|
|
13751
|
+
* @private
|
|
13869
13752
|
*/
|
|
13870
|
-
|
|
13871
|
-
|
|
13872
|
-
|
|
13873
|
-
|
|
13874
|
-
|
|
13875
|
-
response.hasOwnProperty("scope") &&
|
|
13876
|
-
response.hasOwnProperty("expires_in")) {
|
|
13877
|
-
return response;
|
|
13878
|
-
}
|
|
13879
|
-
else {
|
|
13880
|
-
throw createAuthError(unexpectedError, "Response missing expected properties.");
|
|
13881
|
-
}
|
|
13753
|
+
addRequestSKUs(request) {
|
|
13754
|
+
request.extraParameters = {
|
|
13755
|
+
...request.extraParameters,
|
|
13756
|
+
[X_CLIENT_EXTRA_SKU]: this.skus,
|
|
13757
|
+
};
|
|
13882
13758
|
}
|
|
13883
13759
|
/**
|
|
13884
|
-
*
|
|
13885
|
-
* @param
|
|
13886
|
-
* @returns
|
|
13760
|
+
* Acquire token from native platform via browser extension
|
|
13761
|
+
* @param request
|
|
13887
13762
|
*/
|
|
13888
|
-
|
|
13889
|
-
|
|
13763
|
+
async acquireToken(request, cacheLookupPolicy) {
|
|
13764
|
+
this.performanceClient.addQueueMeasurement(PerformanceEvents.NativeInteractionClientAcquireToken, request.correlationId);
|
|
13765
|
+
this.logger.trace("NativeInteractionClient - acquireToken called.");
|
|
13766
|
+
// start the perf measurement
|
|
13767
|
+
const nativeATMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.NativeInteractionClientAcquireToken, request.correlationId);
|
|
13768
|
+
const reqTimestamp = nowSeconds();
|
|
13769
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
13770
|
+
try {
|
|
13771
|
+
// initialize native request
|
|
13772
|
+
const nativeRequest = await this.initializeNativeRequest(request);
|
|
13773
|
+
// check if the tokens can be retrieved from internal cache
|
|
13890
13774
|
try {
|
|
13891
|
-
|
|
13775
|
+
const result = await this.acquireTokensFromCache(this.accountId, nativeRequest);
|
|
13776
|
+
nativeATMeasurement.end({
|
|
13777
|
+
success: true,
|
|
13778
|
+
isNativeBroker: false,
|
|
13779
|
+
fromCache: true,
|
|
13780
|
+
});
|
|
13781
|
+
return result;
|
|
13892
13782
|
}
|
|
13893
13783
|
catch (e) {
|
|
13894
|
-
|
|
13784
|
+
if (cacheLookupPolicy === CacheLookupPolicy.AccessToken) {
|
|
13785
|
+
this.logger.info("MSAL internal Cache does not contain tokens, return error as per cache policy");
|
|
13786
|
+
throw e;
|
|
13787
|
+
}
|
|
13788
|
+
// continue with a native call for any and all errors
|
|
13789
|
+
this.logger.info("MSAL internal Cache does not contain tokens, proceed to make a native call");
|
|
13895
13790
|
}
|
|
13791
|
+
const { ...nativeTokenRequest } = nativeRequest;
|
|
13792
|
+
// fall back to native calls
|
|
13793
|
+
const messageBody = {
|
|
13794
|
+
method: NativeExtensionMethod.GetToken,
|
|
13795
|
+
request: nativeTokenRequest,
|
|
13796
|
+
};
|
|
13797
|
+
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
13798
|
+
const validatedResponse = this.validateNativeResponse(response);
|
|
13799
|
+
return await this.handleNativeResponse(validatedResponse, nativeRequest, reqTimestamp)
|
|
13800
|
+
.then((result) => {
|
|
13801
|
+
nativeATMeasurement.end({
|
|
13802
|
+
success: true,
|
|
13803
|
+
isNativeBroker: true,
|
|
13804
|
+
requestId: result.requestId,
|
|
13805
|
+
});
|
|
13806
|
+
serverTelemetryManager.clearNativeBrokerErrorCode();
|
|
13807
|
+
return result;
|
|
13808
|
+
})
|
|
13809
|
+
.catch((error) => {
|
|
13810
|
+
nativeATMeasurement.end({
|
|
13811
|
+
success: false,
|
|
13812
|
+
errorCode: error.errorCode,
|
|
13813
|
+
subErrorCode: error.subError,
|
|
13814
|
+
isNativeBroker: true,
|
|
13815
|
+
});
|
|
13816
|
+
throw error;
|
|
13817
|
+
});
|
|
13896
13818
|
}
|
|
13897
|
-
|
|
13898
|
-
|
|
13899
|
-
|
|
13900
|
-
|
|
13901
|
-
|
|
13902
|
-
* @returns
|
|
13903
|
-
*/
|
|
13904
|
-
isResponseFromCache(mats) {
|
|
13905
|
-
if (typeof mats.is_cached === "undefined") {
|
|
13906
|
-
this.logger.verbose("NativeInteractionClient - MATS telemetry does not contain field indicating if response was served from cache. Returning false.");
|
|
13907
|
-
return false;
|
|
13819
|
+
catch (e) {
|
|
13820
|
+
if (e instanceof NativeAuthError) {
|
|
13821
|
+
serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode);
|
|
13822
|
+
}
|
|
13823
|
+
throw e;
|
|
13908
13824
|
}
|
|
13909
|
-
return !!mats.is_cached;
|
|
13910
13825
|
}
|
|
13911
13826
|
/**
|
|
13912
|
-
*
|
|
13827
|
+
* Creates silent flow request
|
|
13913
13828
|
* @param request
|
|
13829
|
+
* @param cachedAccount
|
|
13830
|
+
* @returns CommonSilentFlowRequest
|
|
13914
13831
|
*/
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
if (request.account) {
|
|
13919
|
-
// validate authority
|
|
13920
|
-
await this.getDiscoveredAuthority({
|
|
13921
|
-
requestAuthority,
|
|
13922
|
-
requestAzureCloudOptions: request.azureCloudOptions,
|
|
13923
|
-
account: request.account,
|
|
13924
|
-
});
|
|
13925
|
-
}
|
|
13926
|
-
const canonicalAuthority = new UrlString(requestAuthority);
|
|
13927
|
-
canonicalAuthority.validateAsUri();
|
|
13928
|
-
// scopes are expected to be received by the native broker as "scope" and will be added to the request below. Other properties that should be dropped from the request to the native broker can be included in the object destructuring here.
|
|
13929
|
-
const { scopes, ...remainingProperties } = request;
|
|
13930
|
-
const scopeSet = new ScopeSet(scopes || []);
|
|
13931
|
-
scopeSet.appendScopes(OIDC_DEFAULT_SCOPES);
|
|
13932
|
-
const getPrompt = () => {
|
|
13933
|
-
// If request is silent, prompt is always none
|
|
13934
|
-
switch (this.apiId) {
|
|
13935
|
-
case ApiId.ssoSilent:
|
|
13936
|
-
case ApiId.acquireTokenSilent_silentFlow:
|
|
13937
|
-
this.logger.trace("initializeNativeRequest: silent request sets prompt to none");
|
|
13938
|
-
return PromptValue.NONE;
|
|
13939
|
-
}
|
|
13940
|
-
// Prompt not provided, request may proceed and native broker decides if it needs to prompt
|
|
13941
|
-
if (!request.prompt) {
|
|
13942
|
-
this.logger.trace("initializeNativeRequest: prompt was not provided");
|
|
13943
|
-
return undefined;
|
|
13944
|
-
}
|
|
13945
|
-
// If request is interactive, check if prompt provided is allowed to go directly to native broker
|
|
13946
|
-
switch (request.prompt) {
|
|
13947
|
-
case PromptValue.NONE:
|
|
13948
|
-
case PromptValue.CONSENT:
|
|
13949
|
-
case PromptValue.LOGIN:
|
|
13950
|
-
this.logger.trace("initializeNativeRequest: prompt is compatible with native flow");
|
|
13951
|
-
return request.prompt;
|
|
13952
|
-
default:
|
|
13953
|
-
this.logger.trace(`initializeNativeRequest: prompt = ${request.prompt} is not compatible with native flow`);
|
|
13954
|
-
throw createBrowserAuthError(nativePromptNotSupported);
|
|
13955
|
-
}
|
|
13956
|
-
};
|
|
13957
|
-
const validatedRequest = {
|
|
13958
|
-
...remainingProperties,
|
|
13959
|
-
accountId: this.accountId,
|
|
13960
|
-
clientId: this.config.auth.clientId,
|
|
13961
|
-
authority: canonicalAuthority.urlString,
|
|
13962
|
-
scope: scopeSet.printScopes(),
|
|
13963
|
-
redirectUri: this.getRedirectUri(request.redirectUri),
|
|
13964
|
-
prompt: getPrompt(),
|
|
13832
|
+
createSilentCacheRequest(request, cachedAccount) {
|
|
13833
|
+
return {
|
|
13834
|
+
authority: request.authority,
|
|
13965
13835
|
correlationId: this.correlationId,
|
|
13966
|
-
|
|
13967
|
-
|
|
13968
|
-
|
|
13969
|
-
...request.extraQueryParameters,
|
|
13970
|
-
...request.tokenQueryParameters,
|
|
13971
|
-
},
|
|
13972
|
-
extendedExpiryToken: false,
|
|
13973
|
-
keyId: request.popKid,
|
|
13836
|
+
scopes: ScopeSet.fromString(request.scope).asArray(),
|
|
13837
|
+
account: cachedAccount,
|
|
13838
|
+
forceRefresh: false,
|
|
13974
13839
|
};
|
|
13975
|
-
// Check for PoP token requests: signPopToken should only be set to true if popKid is not set
|
|
13976
|
-
if (validatedRequest.signPopToken && !!request.popKid) {
|
|
13977
|
-
throw createBrowserAuthError(invalidPopTokenRequest);
|
|
13978
|
-
}
|
|
13979
|
-
this.handleExtraBrokerParams(validatedRequest);
|
|
13980
|
-
validatedRequest.extraParameters =
|
|
13981
|
-
validatedRequest.extraParameters || {};
|
|
13982
|
-
validatedRequest.extraParameters.telemetry =
|
|
13983
|
-
NativeConstants.MATS_TELEMETRY;
|
|
13984
|
-
if (request.authenticationScheme === AuthenticationScheme.POP) {
|
|
13985
|
-
// add POP request type
|
|
13986
|
-
const shrParameters = {
|
|
13987
|
-
resourceRequestUri: request.resourceRequestUri,
|
|
13988
|
-
resourceRequestMethod: request.resourceRequestMethod,
|
|
13989
|
-
shrClaims: request.shrClaims,
|
|
13990
|
-
shrNonce: request.shrNonce,
|
|
13991
|
-
};
|
|
13992
|
-
const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);
|
|
13993
|
-
// generate reqCnf if not provided in the request
|
|
13994
|
-
let reqCnfData;
|
|
13995
|
-
if (!validatedRequest.keyId) {
|
|
13996
|
-
const generatedReqCnfData = await invokeAsync(popTokenGenerator.generateCnf.bind(popTokenGenerator), PerformanceEvents.PopTokenGenerateCnf, this.logger, this.performanceClient, request.correlationId)(shrParameters, this.logger);
|
|
13997
|
-
reqCnfData = generatedReqCnfData.reqCnfString;
|
|
13998
|
-
validatedRequest.keyId = generatedReqCnfData.kid;
|
|
13999
|
-
validatedRequest.signPopToken = true;
|
|
14000
|
-
}
|
|
14001
|
-
else {
|
|
14002
|
-
reqCnfData = this.browserCrypto.base64UrlEncode(JSON.stringify({ kid: validatedRequest.keyId }));
|
|
14003
|
-
validatedRequest.signPopToken = false;
|
|
14004
|
-
}
|
|
14005
|
-
// SPAs require whole string to be passed to broker
|
|
14006
|
-
validatedRequest.reqCnf = reqCnfData;
|
|
14007
|
-
}
|
|
14008
|
-
this.addRequestSKUs(validatedRequest);
|
|
14009
|
-
return validatedRequest;
|
|
14010
13840
|
}
|
|
14011
13841
|
/**
|
|
14012
|
-
*
|
|
14013
|
-
* @param
|
|
14014
|
-
* @
|
|
13842
|
+
* Fetches the tokens from the cache if un-expired
|
|
13843
|
+
* @param nativeAccountId
|
|
13844
|
+
* @param request
|
|
13845
|
+
* @returns authenticationResult
|
|
14015
13846
|
*/
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
|
|
14019
|
-
|
|
14020
|
-
request.extraParameters.hasOwnProperty(CLIENT_ID);
|
|
14021
|
-
if (!request.embeddedClientId && !hasExtraBrokerParams) {
|
|
14022
|
-
return;
|
|
13847
|
+
async acquireTokensFromCache(nativeAccountId, request) {
|
|
13848
|
+
if (!nativeAccountId) {
|
|
13849
|
+
this.logger.warning("NativeInteractionClient:acquireTokensFromCache - No nativeAccountId provided");
|
|
13850
|
+
throw createClientAuthError(noAccountFound);
|
|
14023
13851
|
}
|
|
14024
|
-
|
|
14025
|
-
const
|
|
14026
|
-
|
|
14027
|
-
|
|
14028
|
-
|
|
13852
|
+
// fetch the account from browser cache
|
|
13853
|
+
const account = this.browserStorage.getBaseAccountInfo({
|
|
13854
|
+
nativeAccountId,
|
|
13855
|
+
});
|
|
13856
|
+
if (!account) {
|
|
13857
|
+
throw createClientAuthError(noAccountFound);
|
|
14029
13858
|
}
|
|
14030
|
-
|
|
14031
|
-
|
|
14032
|
-
|
|
14033
|
-
|
|
14034
|
-
|
|
13859
|
+
// leverage silent flow for cached tokens retrieval
|
|
13860
|
+
try {
|
|
13861
|
+
const silentRequest = this.createSilentCacheRequest(request, account);
|
|
13862
|
+
const result = await this.silentCacheClient.acquireToken(silentRequest);
|
|
13863
|
+
const fullAccount = {
|
|
13864
|
+
...account,
|
|
13865
|
+
idTokenClaims: result?.idTokenClaims,
|
|
13866
|
+
idToken: result?.idToken,
|
|
13867
|
+
};
|
|
13868
|
+
return {
|
|
13869
|
+
...result,
|
|
13870
|
+
account: fullAccount,
|
|
13871
|
+
};
|
|
13872
|
+
}
|
|
13873
|
+
catch (e) {
|
|
13874
|
+
throw e;
|
|
14035
13875
|
}
|
|
14036
|
-
request.extraParameters = {
|
|
14037
|
-
child_client_id,
|
|
14038
|
-
child_redirect_uri,
|
|
14039
|
-
};
|
|
14040
|
-
this.performanceClient?.addFields({
|
|
14041
|
-
embeddedClientId: child_client_id,
|
|
14042
|
-
embeddedRedirectUri: child_redirect_uri,
|
|
14043
|
-
}, request.correlationId);
|
|
14044
|
-
}
|
|
14045
|
-
}
|
|
14046
|
-
|
|
14047
|
-
/*
|
|
14048
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
14049
|
-
* Licensed under the MIT License.
|
|
14050
|
-
*/
|
|
14051
|
-
class NativeMessageHandler {
|
|
14052
|
-
constructor(logger, handshakeTimeoutMs, performanceClient, extensionId) {
|
|
14053
|
-
this.logger = logger;
|
|
14054
|
-
this.handshakeTimeoutMs = handshakeTimeoutMs;
|
|
14055
|
-
this.extensionId = extensionId;
|
|
14056
|
-
this.resolvers = new Map(); // Used for non-handshake messages
|
|
14057
|
-
this.handshakeResolvers = new Map(); // Used for handshake messages
|
|
14058
|
-
this.messageChannel = new MessageChannel();
|
|
14059
|
-
this.windowListener = this.onWindowMessage.bind(this); // Window event callback doesn't have access to 'this' unless it's bound
|
|
14060
|
-
this.performanceClient = performanceClient;
|
|
14061
|
-
this.handshakeEvent = performanceClient.startMeasurement(PerformanceEvents.NativeMessageHandlerHandshake);
|
|
14062
13876
|
}
|
|
14063
13877
|
/**
|
|
14064
|
-
*
|
|
14065
|
-
* @param
|
|
13878
|
+
* Acquires a token from native platform then redirects to the redirectUri instead of returning the response
|
|
13879
|
+
* @param {RedirectRequest} request
|
|
13880
|
+
* @param {InProgressPerformanceEvent} rootMeasurement
|
|
14066
13881
|
*/
|
|
14067
|
-
async
|
|
14068
|
-
this.logger.trace("
|
|
14069
|
-
const
|
|
14070
|
-
|
|
14071
|
-
|
|
14072
|
-
|
|
14073
|
-
|
|
13882
|
+
async acquireTokenRedirect(request, rootMeasurement) {
|
|
13883
|
+
this.logger.trace("NativeInteractionClient - acquireTokenRedirect called.");
|
|
13884
|
+
const { ...remainingParameters } = request;
|
|
13885
|
+
delete remainingParameters.onRedirectNavigate;
|
|
13886
|
+
const nativeRequest = await this.initializeNativeRequest(remainingParameters);
|
|
13887
|
+
const messageBody = {
|
|
13888
|
+
method: NativeExtensionMethod.GetToken,
|
|
13889
|
+
request: nativeRequest,
|
|
14074
13890
|
};
|
|
14075
|
-
|
|
14076
|
-
|
|
14077
|
-
|
|
14078
|
-
|
|
14079
|
-
|
|
14080
|
-
|
|
13891
|
+
try {
|
|
13892
|
+
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
13893
|
+
this.validateNativeResponse(response);
|
|
13894
|
+
}
|
|
13895
|
+
catch (e) {
|
|
13896
|
+
// Only throw fatal errors here to allow application to fallback to regular redirect. Otherwise proceed and the error will be thrown in handleRedirectPromise
|
|
13897
|
+
if (e instanceof NativeAuthError) {
|
|
13898
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
13899
|
+
serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode);
|
|
13900
|
+
if (isFatalNativeAuthError(e)) {
|
|
13901
|
+
throw e;
|
|
13902
|
+
}
|
|
13903
|
+
}
|
|
13904
|
+
}
|
|
13905
|
+
this.browserStorage.setTemporaryCache(TemporaryCacheKeys.NATIVE_REQUEST, JSON.stringify(nativeRequest), true);
|
|
13906
|
+
const navigationOptions = {
|
|
13907
|
+
apiId: ApiId.acquireTokenRedirect,
|
|
13908
|
+
timeout: this.config.system.redirectNavigationTimeout,
|
|
13909
|
+
noHistory: false,
|
|
13910
|
+
};
|
|
13911
|
+
const redirectUri = this.config.auth.navigateToLoginRequestUrl
|
|
13912
|
+
? window.location.href
|
|
13913
|
+
: this.getRedirectUri(request.redirectUri);
|
|
13914
|
+
rootMeasurement.end({ success: true });
|
|
13915
|
+
await this.navigationClient.navigateExternal(redirectUri, navigationOptions); // Need to treat this as external to ensure handleRedirectPromise is run again
|
|
14081
13916
|
}
|
|
14082
13917
|
/**
|
|
14083
|
-
*
|
|
14084
|
-
* @param {
|
|
14085
|
-
* @param {
|
|
14086
|
-
* @param {IPerformanceClient} performanceClient
|
|
14087
|
-
* @param {ICrypto} crypto
|
|
13918
|
+
* If the previous page called native platform for a token using redirect APIs, send the same request again and return the response
|
|
13919
|
+
* @param performanceClient {IPerformanceClient?}
|
|
13920
|
+
* @param correlationId {string?} correlation identifier
|
|
14088
13921
|
*/
|
|
14089
|
-
|
|
14090
|
-
logger.trace("
|
|
13922
|
+
async handleRedirectPromise(performanceClient, correlationId) {
|
|
13923
|
+
this.logger.trace("NativeInteractionClient - handleRedirectPromise called.");
|
|
13924
|
+
if (!this.browserStorage.isInteractionInProgress(true)) {
|
|
13925
|
+
this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
|
|
13926
|
+
return null;
|
|
13927
|
+
}
|
|
13928
|
+
// remove prompt from the request to prevent WAM from prompting twice
|
|
13929
|
+
const cachedRequest = this.browserStorage.getCachedNativeRequest();
|
|
13930
|
+
if (!cachedRequest) {
|
|
13931
|
+
this.logger.verbose("NativeInteractionClient - handleRedirectPromise called but there is no cached request, returning null.");
|
|
13932
|
+
if (performanceClient && correlationId) {
|
|
13933
|
+
performanceClient?.addFields({ errorCode: "no_cached_request" }, correlationId);
|
|
13934
|
+
}
|
|
13935
|
+
return null;
|
|
13936
|
+
}
|
|
13937
|
+
const { prompt, ...request } = cachedRequest;
|
|
13938
|
+
if (prompt) {
|
|
13939
|
+
this.logger.verbose("NativeInteractionClient - handleRedirectPromise called and prompt was included in the original request, removing prompt from cached request to prevent second interaction with native broker window.");
|
|
13940
|
+
}
|
|
13941
|
+
this.browserStorage.removeItem(this.browserStorage.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST));
|
|
13942
|
+
const messageBody = {
|
|
13943
|
+
method: NativeExtensionMethod.GetToken,
|
|
13944
|
+
request: request,
|
|
13945
|
+
};
|
|
13946
|
+
const reqTimestamp = nowSeconds();
|
|
14091
13947
|
try {
|
|
14092
|
-
|
|
14093
|
-
await
|
|
14094
|
-
|
|
13948
|
+
this.logger.verbose("NativeInteractionClient - handleRedirectPromise sending message to native broker.");
|
|
13949
|
+
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
13950
|
+
this.validateNativeResponse(response);
|
|
13951
|
+
const result = this.handleNativeResponse(response, request, reqTimestamp);
|
|
13952
|
+
const res = await result;
|
|
13953
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
13954
|
+
serverTelemetryManager.clearNativeBrokerErrorCode();
|
|
13955
|
+
return res;
|
|
14095
13956
|
}
|
|
14096
13957
|
catch (e) {
|
|
14097
|
-
|
|
14098
|
-
const backupProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient);
|
|
14099
|
-
await backupProvider.sendHandshakeRequest();
|
|
14100
|
-
return backupProvider;
|
|
13958
|
+
throw e;
|
|
14101
13959
|
}
|
|
14102
13960
|
}
|
|
14103
13961
|
/**
|
|
14104
|
-
*
|
|
13962
|
+
* Logout from native platform via browser extension
|
|
13963
|
+
* @param request
|
|
14105
13964
|
*/
|
|
14106
|
-
|
|
14107
|
-
this.logger.trace("
|
|
14108
|
-
|
|
14109
|
-
window.addEventListener("message", this.windowListener, false); // false is important, because content script message processing should work first
|
|
14110
|
-
const req = {
|
|
14111
|
-
channel: NativeConstants.CHANNEL_ID,
|
|
14112
|
-
extensionId: this.extensionId,
|
|
14113
|
-
responseId: createNewGuid(),
|
|
14114
|
-
body: {
|
|
14115
|
-
method: NativeExtensionMethod.HandshakeRequest,
|
|
14116
|
-
},
|
|
14117
|
-
};
|
|
14118
|
-
this.handshakeEvent.add({
|
|
14119
|
-
extensionId: this.extensionId,
|
|
14120
|
-
extensionHandshakeTimeoutMs: this.handshakeTimeoutMs,
|
|
14121
|
-
});
|
|
14122
|
-
this.messageChannel.port1.onmessage = (event) => {
|
|
14123
|
-
this.onChannelMessage(event);
|
|
14124
|
-
};
|
|
14125
|
-
window.postMessage(req, window.origin, [this.messageChannel.port2]);
|
|
14126
|
-
return new Promise((resolve, reject) => {
|
|
14127
|
-
this.handshakeResolvers.set(req.responseId, { resolve, reject });
|
|
14128
|
-
this.timeoutId = window.setTimeout(() => {
|
|
14129
|
-
/*
|
|
14130
|
-
* Throw an error if neither HandshakeResponse nor original Handshake request are received in a reasonable timeframe.
|
|
14131
|
-
* This typically suggests an event handler stopped propagation of the Handshake request but did not respond to it on the MessageChannel port
|
|
14132
|
-
*/
|
|
14133
|
-
window.removeEventListener("message", this.windowListener, false);
|
|
14134
|
-
this.messageChannel.port1.close();
|
|
14135
|
-
this.messageChannel.port2.close();
|
|
14136
|
-
this.handshakeEvent.end({
|
|
14137
|
-
extensionHandshakeTimedOut: true,
|
|
14138
|
-
success: false,
|
|
14139
|
-
});
|
|
14140
|
-
reject(createBrowserAuthError(nativeHandshakeTimeout));
|
|
14141
|
-
this.handshakeResolvers.delete(req.responseId);
|
|
14142
|
-
}, this.handshakeTimeoutMs); // Use a reasonable timeout in milliseconds here
|
|
14143
|
-
});
|
|
13965
|
+
logout() {
|
|
13966
|
+
this.logger.trace("NativeInteractionClient - logout called.");
|
|
13967
|
+
return Promise.reject("Logout not implemented yet");
|
|
14144
13968
|
}
|
|
14145
13969
|
/**
|
|
14146
|
-
*
|
|
14147
|
-
* @param
|
|
13970
|
+
* Transform response from native platform into AuthenticationResult object which will be returned to the end user
|
|
13971
|
+
* @param response
|
|
13972
|
+
* @param request
|
|
13973
|
+
* @param reqTimestamp
|
|
14148
13974
|
*/
|
|
14149
|
-
|
|
14150
|
-
this.logger.trace("
|
|
14151
|
-
//
|
|
14152
|
-
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
|
|
14156
|
-
|
|
14157
|
-
|
|
14158
|
-
|
|
14159
|
-
|
|
14160
|
-
|
|
14161
|
-
return;
|
|
13975
|
+
async handleNativeResponse(response, request, reqTimestamp) {
|
|
13976
|
+
this.logger.trace("NativeInteractionClient - handleNativeResponse called.");
|
|
13977
|
+
// generate identifiers
|
|
13978
|
+
const idTokenClaims = extractTokenClaims(response.id_token, base64Decode);
|
|
13979
|
+
const homeAccountIdentifier = this.createHomeAccountIdentifier(response, idTokenClaims);
|
|
13980
|
+
const cachedhomeAccountId = this.browserStorage.getAccountInfoFilteredBy({
|
|
13981
|
+
nativeAccountId: request.accountId,
|
|
13982
|
+
})?.homeAccountId;
|
|
13983
|
+
// add exception for double brokering, please note this is temporary and will be fortified in future
|
|
13984
|
+
if (request.extraParameters?.child_client_id &&
|
|
13985
|
+
response.account.id !== request.accountId) {
|
|
13986
|
+
this.logger.info("handleNativeServerResponse: Double broker flow detected, ignoring accountId mismatch");
|
|
14162
13987
|
}
|
|
14163
|
-
if (
|
|
14164
|
-
|
|
14165
|
-
|
|
14166
|
-
|
|
14167
|
-
* the proper response.
|
|
14168
|
-
*/
|
|
14169
|
-
if (!handshakeResolver) {
|
|
14170
|
-
this.logger.trace(`NativeMessageHandler.onWindowMessage - resolver can't be found for request ${request.responseId}`);
|
|
14171
|
-
return;
|
|
14172
|
-
}
|
|
14173
|
-
// If we receive this message back it means no extension intercepted the request, meaning no extension supporting handshake protocol is installed
|
|
14174
|
-
this.logger.verbose(request.extensionId
|
|
14175
|
-
? `Extension with id: ${request.extensionId} not installed`
|
|
14176
|
-
: "No extension installed");
|
|
14177
|
-
clearTimeout(this.timeoutId);
|
|
14178
|
-
this.messageChannel.port1.close();
|
|
14179
|
-
this.messageChannel.port2.close();
|
|
14180
|
-
window.removeEventListener("message", this.windowListener, false);
|
|
14181
|
-
this.handshakeEvent.end({
|
|
14182
|
-
success: false,
|
|
14183
|
-
extensionInstalled: false,
|
|
14184
|
-
});
|
|
14185
|
-
handshakeResolver.reject(createBrowserAuthError(nativeExtensionNotInstalled));
|
|
13988
|
+
else if (homeAccountIdentifier !== cachedhomeAccountId &&
|
|
13989
|
+
response.account.id !== request.accountId) {
|
|
13990
|
+
// User switch in native broker prompt is not supported. All users must first sign in through web flow to ensure server state is in sync
|
|
13991
|
+
throw createNativeAuthError(userSwitch);
|
|
14186
13992
|
}
|
|
13993
|
+
// Get the preferred_cache domain for the given authority
|
|
13994
|
+
const authority = await this.getDiscoveredAuthority({
|
|
13995
|
+
requestAuthority: request.authority,
|
|
13996
|
+
});
|
|
13997
|
+
const baseAccount = buildAccountToCache(this.browserStorage, authority, homeAccountIdentifier, base64Decode, idTokenClaims, response.client_info, undefined, // environment
|
|
13998
|
+
idTokenClaims.tid, undefined, // auth code payload
|
|
13999
|
+
response.account.id, this.logger);
|
|
14000
|
+
// Ensure expires_in is in number format
|
|
14001
|
+
response.expires_in = Number(response.expires_in);
|
|
14002
|
+
// generate authenticationResult
|
|
14003
|
+
const result = await this.generateAuthenticationResult(response, request, idTokenClaims, baseAccount, authority.canonicalAuthority, reqTimestamp);
|
|
14004
|
+
// cache accounts and tokens in the appropriate storage
|
|
14005
|
+
await this.cacheAccount(baseAccount);
|
|
14006
|
+
await this.cacheNativeTokens(response, request, homeAccountIdentifier, idTokenClaims, response.access_token, result.tenantId, reqTimestamp);
|
|
14007
|
+
return result;
|
|
14187
14008
|
}
|
|
14188
14009
|
/**
|
|
14189
|
-
*
|
|
14190
|
-
* @param
|
|
14010
|
+
* creates an homeAccountIdentifier for the account
|
|
14011
|
+
* @param response
|
|
14012
|
+
* @param idTokenObj
|
|
14013
|
+
* @returns
|
|
14191
14014
|
*/
|
|
14192
|
-
|
|
14193
|
-
|
|
14194
|
-
const
|
|
14195
|
-
|
|
14196
|
-
|
|
14197
|
-
|
|
14198
|
-
|
|
14199
|
-
|
|
14200
|
-
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14204
|
-
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14015
|
+
createHomeAccountIdentifier(response, idTokenClaims) {
|
|
14016
|
+
// Save account in browser storage
|
|
14017
|
+
const homeAccountIdentifier = AccountEntity.generateHomeAccountId(response.client_info || Constants.EMPTY_STRING, AuthorityType.Default, this.logger, this.browserCrypto, idTokenClaims);
|
|
14018
|
+
return homeAccountIdentifier;
|
|
14019
|
+
}
|
|
14020
|
+
/**
|
|
14021
|
+
* Helper to generate scopes
|
|
14022
|
+
* @param response
|
|
14023
|
+
* @param request
|
|
14024
|
+
* @returns
|
|
14025
|
+
*/
|
|
14026
|
+
generateScopes(response, request) {
|
|
14027
|
+
return response.scope
|
|
14028
|
+
? ScopeSet.fromString(response.scope)
|
|
14029
|
+
: ScopeSet.fromString(request.scope);
|
|
14030
|
+
}
|
|
14031
|
+
/**
|
|
14032
|
+
* If PoP token is requesred, records the PoP token if returned from the WAM, else generates one in the browser
|
|
14033
|
+
* @param request
|
|
14034
|
+
* @param response
|
|
14035
|
+
*/
|
|
14036
|
+
async generatePopAccessToken(response, request) {
|
|
14037
|
+
if (request.tokenType === AuthenticationScheme.POP &&
|
|
14038
|
+
request.signPopToken) {
|
|
14039
|
+
/**
|
|
14040
|
+
* This code prioritizes SHR returned from the native layer. In case of error/SHR not calculated from WAM and the AT
|
|
14041
|
+
* is still received, SHR is calculated locally
|
|
14042
|
+
*/
|
|
14043
|
+
// Check if native layer returned an SHR token
|
|
14044
|
+
if (response.shr) {
|
|
14045
|
+
this.logger.trace("handleNativeServerResponse: SHR is enabled in native layer");
|
|
14046
|
+
return response.shr;
|
|
14222
14047
|
}
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
handshakeResolver.resolve();
|
|
14238
|
-
this.handshakeResolvers.delete(request.responseId);
|
|
14048
|
+
// Generate SHR in msal js if WAM does not compute it when POP is enabled
|
|
14049
|
+
const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);
|
|
14050
|
+
const shrParameters = {
|
|
14051
|
+
resourceRequestMethod: request.resourceRequestMethod,
|
|
14052
|
+
resourceRequestUri: request.resourceRequestUri,
|
|
14053
|
+
shrClaims: request.shrClaims,
|
|
14054
|
+
shrNonce: request.shrNonce,
|
|
14055
|
+
};
|
|
14056
|
+
/**
|
|
14057
|
+
* KeyID must be present in the native request from when the PoP key was generated in order for
|
|
14058
|
+
* PopTokenGenerator to query the full key for signing
|
|
14059
|
+
*/
|
|
14060
|
+
if (!request.keyId) {
|
|
14061
|
+
throw createClientAuthError(keyIdMissing);
|
|
14239
14062
|
}
|
|
14240
|
-
|
|
14063
|
+
return popTokenGenerator.signPopToken(response.access_token, request.keyId, shrParameters);
|
|
14241
14064
|
}
|
|
14242
|
-
|
|
14243
|
-
|
|
14244
|
-
this.logger.errorPii(`Error parsing response from WAM Extension: ${err}`);
|
|
14245
|
-
this.logger.errorPii(`Unable to parse ${event}`);
|
|
14246
|
-
if (resolver) {
|
|
14247
|
-
resolver.reject(err);
|
|
14248
|
-
}
|
|
14249
|
-
else if (handshakeResolver) {
|
|
14250
|
-
handshakeResolver.reject(err);
|
|
14251
|
-
}
|
|
14065
|
+
else {
|
|
14066
|
+
return response.access_token;
|
|
14252
14067
|
}
|
|
14253
14068
|
}
|
|
14254
14069
|
/**
|
|
14255
|
-
*
|
|
14070
|
+
* Generates authentication result
|
|
14071
|
+
* @param response
|
|
14072
|
+
* @param request
|
|
14073
|
+
* @param idTokenObj
|
|
14074
|
+
* @param accountEntity
|
|
14075
|
+
* @param authority
|
|
14076
|
+
* @param reqTimestamp
|
|
14256
14077
|
* @returns
|
|
14257
14078
|
*/
|
|
14258
|
-
|
|
14259
|
-
|
|
14079
|
+
async generateAuthenticationResult(response, request, idTokenClaims, accountEntity, authority, reqTimestamp) {
|
|
14080
|
+
// Add Native Broker fields to Telemetry
|
|
14081
|
+
const mats = this.addTelemetryFromNativeResponse(response);
|
|
14082
|
+
// If scopes not returned in server response, use request scopes
|
|
14083
|
+
const responseScopes = response.scope
|
|
14084
|
+
? ScopeSet.fromString(response.scope)
|
|
14085
|
+
: ScopeSet.fromString(request.scope);
|
|
14086
|
+
const accountProperties = response.account.properties || {};
|
|
14087
|
+
const uid = accountProperties["UID"] ||
|
|
14088
|
+
idTokenClaims.oid ||
|
|
14089
|
+
idTokenClaims.sub ||
|
|
14090
|
+
Constants.EMPTY_STRING;
|
|
14091
|
+
const tid = accountProperties["TenantId"] ||
|
|
14092
|
+
idTokenClaims.tid ||
|
|
14093
|
+
Constants.EMPTY_STRING;
|
|
14094
|
+
const accountInfo = updateAccountTenantProfileData(accountEntity.getAccountInfo(), undefined, // tenantProfile optional
|
|
14095
|
+
idTokenClaims, response.id_token);
|
|
14096
|
+
/**
|
|
14097
|
+
* In pairwise broker flows, this check prevents the broker's native account id
|
|
14098
|
+
* from being returned over the embedded app's account id.
|
|
14099
|
+
*/
|
|
14100
|
+
if (accountInfo.nativeAccountId !== response.account.id) {
|
|
14101
|
+
accountInfo.nativeAccountId = response.account.id;
|
|
14102
|
+
}
|
|
14103
|
+
// generate PoP token as needed
|
|
14104
|
+
const responseAccessToken = await this.generatePopAccessToken(response, request);
|
|
14105
|
+
const tokenType = request.tokenType === AuthenticationScheme.POP
|
|
14106
|
+
? AuthenticationScheme.POP
|
|
14107
|
+
: AuthenticationScheme.BEARER;
|
|
14108
|
+
const result = {
|
|
14109
|
+
authority: authority,
|
|
14110
|
+
uniqueId: uid,
|
|
14111
|
+
tenantId: tid,
|
|
14112
|
+
scopes: responseScopes.asArray(),
|
|
14113
|
+
account: accountInfo,
|
|
14114
|
+
idToken: response.id_token,
|
|
14115
|
+
idTokenClaims: idTokenClaims,
|
|
14116
|
+
accessToken: responseAccessToken,
|
|
14117
|
+
fromCache: mats ? this.isResponseFromCache(mats) : false,
|
|
14118
|
+
// Request timestamp and NativeResponse expires_in are in seconds, converting to Date for AuthenticationResult
|
|
14119
|
+
expiresOn: toDateFromSeconds(reqTimestamp + response.expires_in),
|
|
14120
|
+
tokenType: tokenType,
|
|
14121
|
+
correlationId: this.correlationId,
|
|
14122
|
+
state: response.state,
|
|
14123
|
+
fromNativeBroker: true,
|
|
14124
|
+
};
|
|
14125
|
+
return result;
|
|
14260
14126
|
}
|
|
14261
14127
|
/**
|
|
14262
|
-
*
|
|
14263
|
-
* @
|
|
14128
|
+
* cache the account entity in browser storage
|
|
14129
|
+
* @param accountEntity
|
|
14264
14130
|
*/
|
|
14265
|
-
|
|
14266
|
-
|
|
14131
|
+
async cacheAccount(accountEntity) {
|
|
14132
|
+
// Store the account info and hence `nativeAccountId` in browser cache
|
|
14133
|
+
await this.browserStorage.setAccount(accountEntity, this.correlationId);
|
|
14134
|
+
// Remove any existing cached tokens for this account in browser storage
|
|
14135
|
+
this.browserStorage.removeAccountContext(accountEntity).catch((e) => {
|
|
14136
|
+
this.logger.error(`Error occurred while removing account context from browser storage. ${e}`);
|
|
14137
|
+
});
|
|
14267
14138
|
}
|
|
14268
14139
|
/**
|
|
14269
|
-
*
|
|
14270
|
-
* @param
|
|
14271
|
-
* @param
|
|
14272
|
-
* @param
|
|
14273
|
-
* @param
|
|
14140
|
+
* Stores the access_token and id_token in inmemory storage
|
|
14141
|
+
* @param response
|
|
14142
|
+
* @param request
|
|
14143
|
+
* @param homeAccountIdentifier
|
|
14144
|
+
* @param idTokenObj
|
|
14145
|
+
* @param responseAccessToken
|
|
14146
|
+
* @param tenantId
|
|
14147
|
+
* @param reqTimestamp
|
|
14274
14148
|
*/
|
|
14275
|
-
|
|
14276
|
-
|
|
14277
|
-
|
|
14278
|
-
|
|
14279
|
-
|
|
14280
|
-
|
|
14149
|
+
cacheNativeTokens(response, request, homeAccountIdentifier, idTokenClaims, responseAccessToken, tenantId, reqTimestamp) {
|
|
14150
|
+
const cachedIdToken = createIdTokenEntity(homeAccountIdentifier, request.authority, response.id_token || "", request.clientId, idTokenClaims.tid || "");
|
|
14151
|
+
// cache accessToken in inmemory storage
|
|
14152
|
+
const expiresIn = request.tokenType === AuthenticationScheme.POP
|
|
14153
|
+
? Constants.SHR_NONCE_VALIDITY
|
|
14154
|
+
: (typeof response.expires_in === "string"
|
|
14155
|
+
? parseInt(response.expires_in, 10)
|
|
14156
|
+
: response.expires_in) || 0;
|
|
14157
|
+
const tokenExpirationSeconds = reqTimestamp + expiresIn;
|
|
14158
|
+
const responseScopes = this.generateScopes(response, request);
|
|
14159
|
+
const cachedAccessToken = createAccessTokenEntity(homeAccountIdentifier, request.authority, responseAccessToken, request.clientId, idTokenClaims.tid || tenantId, responseScopes.printScopes(), tokenExpirationSeconds, 0, base64Decode, undefined, request.tokenType, undefined, request.keyId);
|
|
14160
|
+
const nativeCacheRecord = {
|
|
14161
|
+
idToken: cachedIdToken,
|
|
14162
|
+
accessToken: cachedAccessToken,
|
|
14163
|
+
};
|
|
14164
|
+
return this.nativeStorageManager.saveCacheRecord(nativeCacheRecord, this.correlationId, request.storeInCache);
|
|
14165
|
+
}
|
|
14166
|
+
addTelemetryFromNativeResponse(response) {
|
|
14167
|
+
const mats = this.getMATSFromResponse(response);
|
|
14168
|
+
if (!mats) {
|
|
14169
|
+
return null;
|
|
14281
14170
|
}
|
|
14282
|
-
|
|
14283
|
-
|
|
14284
|
-
|
|
14285
|
-
|
|
14171
|
+
this.performanceClient.addFields({
|
|
14172
|
+
extensionId: this.nativeMessageHandler.getExtensionId(),
|
|
14173
|
+
extensionVersion: this.nativeMessageHandler.getExtensionVersion(),
|
|
14174
|
+
matsBrokerVersion: mats.broker_version,
|
|
14175
|
+
matsAccountJoinOnStart: mats.account_join_on_start,
|
|
14176
|
+
matsAccountJoinOnEnd: mats.account_join_on_end,
|
|
14177
|
+
matsDeviceJoin: mats.device_join,
|
|
14178
|
+
matsPromptBehavior: mats.prompt_behavior,
|
|
14179
|
+
matsApiErrorCode: mats.api_error_code,
|
|
14180
|
+
matsUiVisible: mats.ui_visible,
|
|
14181
|
+
matsSilentCode: mats.silent_code,
|
|
14182
|
+
matsSilentBiSubCode: mats.silent_bi_sub_code,
|
|
14183
|
+
matsSilentMessage: mats.silent_message,
|
|
14184
|
+
matsSilentStatus: mats.silent_status,
|
|
14185
|
+
matsHttpStatus: mats.http_status,
|
|
14186
|
+
matsHttpEventCount: mats.http_event_count,
|
|
14187
|
+
}, this.correlationId);
|
|
14188
|
+
return mats;
|
|
14189
|
+
}
|
|
14190
|
+
/**
|
|
14191
|
+
* Validates native platform response before processing
|
|
14192
|
+
* @param response
|
|
14193
|
+
*/
|
|
14194
|
+
validateNativeResponse(response) {
|
|
14195
|
+
if (response.hasOwnProperty("access_token") &&
|
|
14196
|
+
response.hasOwnProperty("id_token") &&
|
|
14197
|
+
response.hasOwnProperty("client_info") &&
|
|
14198
|
+
response.hasOwnProperty("account") &&
|
|
14199
|
+
response.hasOwnProperty("scope") &&
|
|
14200
|
+
response.hasOwnProperty("expires_in")) {
|
|
14201
|
+
return response;
|
|
14286
14202
|
}
|
|
14287
|
-
|
|
14288
|
-
|
|
14289
|
-
case AuthenticationScheme.BEARER:
|
|
14290
|
-
case AuthenticationScheme.POP:
|
|
14291
|
-
logger.trace("isPlatformBrokerAvailable: authenticationScheme is supported, returning true");
|
|
14292
|
-
return true;
|
|
14293
|
-
default:
|
|
14294
|
-
logger.trace("isPlatformBrokerAvailable: authenticationScheme is not supported, returning false");
|
|
14295
|
-
return false;
|
|
14296
|
-
}
|
|
14203
|
+
else {
|
|
14204
|
+
throw createAuthError(unexpectedError, "Response missing expected properties.");
|
|
14297
14205
|
}
|
|
14298
|
-
return true;
|
|
14299
|
-
}
|
|
14300
|
-
}
|
|
14301
|
-
|
|
14302
|
-
/*
|
|
14303
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
14304
|
-
* Licensed under the MIT License.
|
|
14305
|
-
*/
|
|
14306
|
-
/**
|
|
14307
|
-
* Abstract class which defines operations for a browser interaction handling class.
|
|
14308
|
-
*/
|
|
14309
|
-
class InteractionHandler {
|
|
14310
|
-
constructor(authCodeModule, storageImpl, authCodeRequest, logger, performanceClient) {
|
|
14311
|
-
this.authModule = authCodeModule;
|
|
14312
|
-
this.browserStorage = storageImpl;
|
|
14313
|
-
this.authCodeRequest = authCodeRequest;
|
|
14314
|
-
this.logger = logger;
|
|
14315
|
-
this.performanceClient = performanceClient;
|
|
14316
14206
|
}
|
|
14317
14207
|
/**
|
|
14318
|
-
*
|
|
14319
|
-
* @param
|
|
14208
|
+
* Gets MATS telemetry from native response
|
|
14209
|
+
* @param response
|
|
14210
|
+
* @returns
|
|
14320
14211
|
*/
|
|
14321
|
-
|
|
14322
|
-
|
|
14323
|
-
|
|
14324
|
-
|
|
14325
|
-
authCodeResponse = getAuthorizationCodePayload(response, request.state);
|
|
14326
|
-
}
|
|
14327
|
-
catch (e) {
|
|
14328
|
-
if (e instanceof ServerError &&
|
|
14329
|
-
e.subError === userCancelled) {
|
|
14330
|
-
// Translate server error caused by user closing native prompt to corresponding first class MSAL error
|
|
14331
|
-
throw createBrowserAuthError(userCancelled);
|
|
14212
|
+
getMATSFromResponse(response) {
|
|
14213
|
+
if (response.properties.MATS) {
|
|
14214
|
+
try {
|
|
14215
|
+
return JSON.parse(response.properties.MATS);
|
|
14332
14216
|
}
|
|
14333
|
-
|
|
14334
|
-
|
|
14217
|
+
catch (e) {
|
|
14218
|
+
this.logger.error("NativeInteractionClient - Error parsing MATS telemetry, returning null instead");
|
|
14335
14219
|
}
|
|
14336
14220
|
}
|
|
14337
|
-
return
|
|
14221
|
+
return null;
|
|
14338
14222
|
}
|
|
14339
14223
|
/**
|
|
14340
|
-
*
|
|
14341
|
-
* @param
|
|
14342
|
-
* @param state
|
|
14343
|
-
* @param authority
|
|
14344
|
-
* @param networkModule
|
|
14224
|
+
* Returns whether or not response came from native cache
|
|
14225
|
+
* @param response
|
|
14345
14226
|
* @returns
|
|
14346
14227
|
*/
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
|
|
14350
|
-
|
|
14351
|
-
this.authCodeRequest.code = authCodeResponse.code;
|
|
14352
|
-
// Check for new cloud instance
|
|
14353
|
-
if (authCodeResponse.cloud_instance_host_name) {
|
|
14354
|
-
await invokeAsync(this.authModule.updateAuthority.bind(this.authModule), PerformanceEvents.UpdateTokenEndpointAuthority, this.logger, this.performanceClient, request.correlationId)(authCodeResponse.cloud_instance_host_name, request.correlationId);
|
|
14355
|
-
}
|
|
14356
|
-
// Nonce validation not needed when redirect not involved (e.g. hybrid spa, renewing token via rt)
|
|
14357
|
-
if (validateNonce) {
|
|
14358
|
-
// TODO: Assigning "response nonce" to "request nonce" is confusing. Refactor the function doing validation to accept request nonce directly
|
|
14359
|
-
authCodeResponse.nonce = request.nonce || undefined;
|
|
14360
|
-
}
|
|
14361
|
-
authCodeResponse.state = request.state;
|
|
14362
|
-
// Add CCS parameters if available
|
|
14363
|
-
if (authCodeResponse.client_info) {
|
|
14364
|
-
this.authCodeRequest.clientInfo = authCodeResponse.client_info;
|
|
14365
|
-
}
|
|
14366
|
-
else {
|
|
14367
|
-
const ccsCred = this.createCcsCredentials(request);
|
|
14368
|
-
if (ccsCred) {
|
|
14369
|
-
this.authCodeRequest.ccsCredential = ccsCred;
|
|
14370
|
-
}
|
|
14228
|
+
isResponseFromCache(mats) {
|
|
14229
|
+
if (typeof mats.is_cached === "undefined") {
|
|
14230
|
+
this.logger.verbose("NativeInteractionClient - MATS telemetry does not contain field indicating if response was served from cache. Returning false.");
|
|
14231
|
+
return false;
|
|
14371
14232
|
}
|
|
14372
|
-
|
|
14373
|
-
const tokenResponse = (await invokeAsync(this.authModule.acquireToken.bind(this.authModule), PerformanceEvents.AuthClientAcquireToken, this.logger, this.performanceClient, request.correlationId)(this.authCodeRequest, authCodeResponse));
|
|
14374
|
-
return tokenResponse;
|
|
14233
|
+
return !!mats.is_cached;
|
|
14375
14234
|
}
|
|
14376
14235
|
/**
|
|
14377
|
-
*
|
|
14236
|
+
* Translates developer provided request object into NativeRequest object
|
|
14237
|
+
* @param request
|
|
14378
14238
|
*/
|
|
14379
|
-
|
|
14239
|
+
async initializeNativeRequest(request) {
|
|
14240
|
+
this.logger.trace("NativeInteractionClient - initializeNativeRequest called");
|
|
14241
|
+
const requestAuthority = request.authority || this.config.auth.authority;
|
|
14380
14242
|
if (request.account) {
|
|
14381
|
-
|
|
14382
|
-
|
|
14383
|
-
|
|
14384
|
-
|
|
14243
|
+
// validate authority
|
|
14244
|
+
await this.getDiscoveredAuthority({
|
|
14245
|
+
requestAuthority,
|
|
14246
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
14247
|
+
account: request.account,
|
|
14248
|
+
});
|
|
14385
14249
|
}
|
|
14386
|
-
|
|
14387
|
-
|
|
14388
|
-
|
|
14389
|
-
|
|
14250
|
+
const canonicalAuthority = new UrlString(requestAuthority);
|
|
14251
|
+
canonicalAuthority.validateAsUri();
|
|
14252
|
+
// scopes are expected to be received by the native broker as "scope" and will be added to the request below. Other properties that should be dropped from the request to the native broker can be included in the object destructuring here.
|
|
14253
|
+
const { scopes, ...remainingProperties } = request;
|
|
14254
|
+
const scopeSet = new ScopeSet(scopes || []);
|
|
14255
|
+
scopeSet.appendScopes(OIDC_DEFAULT_SCOPES);
|
|
14256
|
+
const getPrompt = () => {
|
|
14257
|
+
// If request is silent, prompt is always none
|
|
14258
|
+
switch (this.apiId) {
|
|
14259
|
+
case ApiId.ssoSilent:
|
|
14260
|
+
case ApiId.acquireTokenSilent_silentFlow:
|
|
14261
|
+
this.logger.trace("initializeNativeRequest: silent request sets prompt to none");
|
|
14262
|
+
return PromptValue.NONE;
|
|
14263
|
+
}
|
|
14264
|
+
// Prompt not provided, request may proceed and native broker decides if it needs to prompt
|
|
14265
|
+
if (!request.prompt) {
|
|
14266
|
+
this.logger.trace("initializeNativeRequest: prompt was not provided");
|
|
14267
|
+
return undefined;
|
|
14268
|
+
}
|
|
14269
|
+
// If request is interactive, check if prompt provided is allowed to go directly to native broker
|
|
14270
|
+
switch (request.prompt) {
|
|
14271
|
+
case PromptValue.NONE:
|
|
14272
|
+
case PromptValue.CONSENT:
|
|
14273
|
+
case PromptValue.LOGIN:
|
|
14274
|
+
this.logger.trace("initializeNativeRequest: prompt is compatible with native flow");
|
|
14275
|
+
return request.prompt;
|
|
14276
|
+
default:
|
|
14277
|
+
this.logger.trace(`initializeNativeRequest: prompt = ${request.prompt} is not compatible with native flow`);
|
|
14278
|
+
throw createBrowserAuthError(nativePromptNotSupported);
|
|
14279
|
+
}
|
|
14280
|
+
};
|
|
14281
|
+
const validatedRequest = {
|
|
14282
|
+
...remainingProperties,
|
|
14283
|
+
accountId: this.accountId,
|
|
14284
|
+
clientId: this.config.auth.clientId,
|
|
14285
|
+
authority: canonicalAuthority.urlString,
|
|
14286
|
+
scope: scopeSet.printScopes(),
|
|
14287
|
+
redirectUri: this.getRedirectUri(request.redirectUri),
|
|
14288
|
+
prompt: getPrompt(),
|
|
14289
|
+
correlationId: this.correlationId,
|
|
14290
|
+
tokenType: request.authenticationScheme,
|
|
14291
|
+
windowTitleSubstring: document.title,
|
|
14292
|
+
extraParameters: {
|
|
14293
|
+
...request.extraQueryParameters,
|
|
14294
|
+
...request.tokenQueryParameters,
|
|
14295
|
+
},
|
|
14296
|
+
extendedExpiryToken: false,
|
|
14297
|
+
keyId: request.popKid,
|
|
14298
|
+
};
|
|
14299
|
+
// Check for PoP token requests: signPopToken should only be set to true if popKid is not set
|
|
14300
|
+
if (validatedRequest.signPopToken && !!request.popKid) {
|
|
14301
|
+
throw createBrowserAuthError(invalidPopTokenRequest);
|
|
14302
|
+
}
|
|
14303
|
+
this.handleExtraBrokerParams(validatedRequest);
|
|
14304
|
+
validatedRequest.extraParameters =
|
|
14305
|
+
validatedRequest.extraParameters || {};
|
|
14306
|
+
validatedRequest.extraParameters.telemetry =
|
|
14307
|
+
NativeConstants.MATS_TELEMETRY;
|
|
14308
|
+
if (request.authenticationScheme === AuthenticationScheme.POP) {
|
|
14309
|
+
// add POP request type
|
|
14310
|
+
const shrParameters = {
|
|
14311
|
+
resourceRequestUri: request.resourceRequestUri,
|
|
14312
|
+
resourceRequestMethod: request.resourceRequestMethod,
|
|
14313
|
+
shrClaims: request.shrClaims,
|
|
14314
|
+
shrNonce: request.shrNonce,
|
|
14390
14315
|
};
|
|
14316
|
+
const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);
|
|
14317
|
+
// generate reqCnf if not provided in the request
|
|
14318
|
+
let reqCnfData;
|
|
14319
|
+
if (!validatedRequest.keyId) {
|
|
14320
|
+
const generatedReqCnfData = await invokeAsync(popTokenGenerator.generateCnf.bind(popTokenGenerator), PerformanceEvents.PopTokenGenerateCnf, this.logger, this.performanceClient, request.correlationId)(shrParameters, this.logger);
|
|
14321
|
+
reqCnfData = generatedReqCnfData.reqCnfString;
|
|
14322
|
+
validatedRequest.keyId = generatedReqCnfData.kid;
|
|
14323
|
+
validatedRequest.signPopToken = true;
|
|
14324
|
+
}
|
|
14325
|
+
else {
|
|
14326
|
+
reqCnfData = this.browserCrypto.base64UrlEncode(JSON.stringify({ kid: validatedRequest.keyId }));
|
|
14327
|
+
validatedRequest.signPopToken = false;
|
|
14328
|
+
}
|
|
14329
|
+
// SPAs require whole string to be passed to broker
|
|
14330
|
+
validatedRequest.reqCnf = reqCnfData;
|
|
14391
14331
|
}
|
|
14392
|
-
|
|
14332
|
+
this.addRequestSKUs(validatedRequest);
|
|
14333
|
+
return validatedRequest;
|
|
14393
14334
|
}
|
|
14394
|
-
|
|
14395
|
-
|
|
14396
|
-
|
|
14397
|
-
|
|
14398
|
-
|
|
14399
|
-
|
|
14400
|
-
|
|
14401
|
-
|
|
14402
|
-
|
|
14403
|
-
|
|
14404
|
-
if (!
|
|
14405
|
-
|
|
14406
|
-
logger.error(`The request has returned to the redirectUri but a ${responseLocation} is not present. It's likely that the ${responseLocation} has been removed or the page has been redirected by code running on the redirectUri page.`);
|
|
14407
|
-
throw createBrowserAuthError(hashEmptyError);
|
|
14335
|
+
/**
|
|
14336
|
+
* Handles extra broker request parameters
|
|
14337
|
+
* @param request {NativeTokenRequest}
|
|
14338
|
+
* @private
|
|
14339
|
+
*/
|
|
14340
|
+
handleExtraBrokerParams(request) {
|
|
14341
|
+
const hasExtraBrokerParams = request.extraParameters &&
|
|
14342
|
+
request.extraParameters.hasOwnProperty(BROKER_CLIENT_ID) &&
|
|
14343
|
+
request.extraParameters.hasOwnProperty(BROKER_REDIRECT_URI) &&
|
|
14344
|
+
request.extraParameters.hasOwnProperty(CLIENT_ID);
|
|
14345
|
+
if (!request.embeddedClientId && !hasExtraBrokerParams) {
|
|
14346
|
+
return;
|
|
14408
14347
|
}
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
|
|
14348
|
+
let child_client_id = "";
|
|
14349
|
+
const child_redirect_uri = request.redirectUri;
|
|
14350
|
+
if (request.embeddedClientId) {
|
|
14351
|
+
request.redirectUri = this.config.auth.redirectUri;
|
|
14352
|
+
child_client_id = request.embeddedClientId;
|
|
14413
14353
|
}
|
|
14414
|
-
|
|
14415
|
-
|
|
14416
|
-
|
|
14417
|
-
|
|
14418
|
-
|
|
14419
|
-
|
|
14420
|
-
|
|
14421
|
-
|
|
14422
|
-
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
14426
|
-
|
|
14427
|
-
|
|
14428
|
-
if (platformStateObj.interactionType !== interactionType) {
|
|
14429
|
-
throw createBrowserAuthError(stateInteractionTypeMismatch);
|
|
14354
|
+
else if (request.extraParameters) {
|
|
14355
|
+
request.redirectUri =
|
|
14356
|
+
request.extraParameters[BROKER_REDIRECT_URI];
|
|
14357
|
+
child_client_id =
|
|
14358
|
+
request.extraParameters[CLIENT_ID];
|
|
14359
|
+
}
|
|
14360
|
+
request.extraParameters = {
|
|
14361
|
+
child_client_id,
|
|
14362
|
+
child_redirect_uri,
|
|
14363
|
+
};
|
|
14364
|
+
this.performanceClient?.addFields({
|
|
14365
|
+
embeddedClientId: child_client_id,
|
|
14366
|
+
embeddedRedirectUri: child_redirect_uri,
|
|
14367
|
+
}, request.correlationId);
|
|
14430
14368
|
}
|
|
14431
14369
|
}
|
|
14432
14370
|
|
|
@@ -14490,9 +14428,147 @@ async function getAuthCodeRequestUrl(config, authority, request, logger, perform
|
|
|
14490
14428
|
throw createClientConfigurationError(pkceParamsMissing);
|
|
14491
14429
|
}
|
|
14492
14430
|
const parameters = await invokeAsync(getStandardParameters, PerformanceEvents.GetStandardParams, logger, performanceClient, request.correlationId)(config, authority, request, logger, performanceClient);
|
|
14493
|
-
|
|
14431
|
+
addResponseType(parameters, OAuthResponseType.CODE);
|
|
14494
14432
|
addCodeChallengeParams(parameters, request.codeChallenge, Constants.S256_CODE_CHALLENGE_METHOD);
|
|
14433
|
+
addExtraQueryParameters(parameters, request.extraQueryParameters || {});
|
|
14495
14434
|
return getAuthorizeUrl(authority, parameters);
|
|
14435
|
+
}
|
|
14436
|
+
/**
|
|
14437
|
+
* Gets the form that will be posted to /authorize with request parameters when using EAR
|
|
14438
|
+
*/
|
|
14439
|
+
async function getEARForm(frame, config, authority, request, logger, performanceClient) {
|
|
14440
|
+
if (!request.earJwk) {
|
|
14441
|
+
throw createBrowserAuthError(earJwkEmpty);
|
|
14442
|
+
}
|
|
14443
|
+
const parameters = await getStandardParameters(config, authority, request, logger, performanceClient);
|
|
14444
|
+
addResponseType(parameters, OAuthResponseType.IDTOKEN_TOKEN_REFRESHTOKEN);
|
|
14445
|
+
addEARParameters(parameters, request.earJwk);
|
|
14446
|
+
const queryParams = new Map();
|
|
14447
|
+
addExtraQueryParameters(queryParams, request.extraQueryParameters || {});
|
|
14448
|
+
const url = getAuthorizeUrl(authority, queryParams);
|
|
14449
|
+
return createForm(frame, url, parameters);
|
|
14450
|
+
}
|
|
14451
|
+
/**
|
|
14452
|
+
* Creates form element in the provided document with auth parameters in the post body
|
|
14453
|
+
* @param frame
|
|
14454
|
+
* @param authorizeUrl
|
|
14455
|
+
* @param parameters
|
|
14456
|
+
* @returns
|
|
14457
|
+
*/
|
|
14458
|
+
function createForm(frame, authorizeUrl, parameters) {
|
|
14459
|
+
const form = frame.createElement("form");
|
|
14460
|
+
form.method = "post";
|
|
14461
|
+
form.action = authorizeUrl;
|
|
14462
|
+
parameters.forEach((value, key) => {
|
|
14463
|
+
const param = frame.createElement("input");
|
|
14464
|
+
param.hidden = true;
|
|
14465
|
+
param.name = key;
|
|
14466
|
+
param.value = value;
|
|
14467
|
+
form.appendChild(param);
|
|
14468
|
+
});
|
|
14469
|
+
frame.body.appendChild(form);
|
|
14470
|
+
return form;
|
|
14471
|
+
}
|
|
14472
|
+
/**
|
|
14473
|
+
* Response handler when server returns accountId on the /authorize request
|
|
14474
|
+
* @param request
|
|
14475
|
+
* @param accountId
|
|
14476
|
+
* @param apiId
|
|
14477
|
+
* @param config
|
|
14478
|
+
* @param browserStorage
|
|
14479
|
+
* @param nativeStorage
|
|
14480
|
+
* @param eventHandler
|
|
14481
|
+
* @param logger
|
|
14482
|
+
* @param performanceClient
|
|
14483
|
+
* @param nativeMessageHandler
|
|
14484
|
+
* @returns
|
|
14485
|
+
*/
|
|
14486
|
+
async function handleResponsePlatformBroker(request, accountId, apiId, config, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler) {
|
|
14487
|
+
if (!nativeMessageHandler) {
|
|
14488
|
+
throw createBrowserAuthError(nativeConnectionNotEstablished);
|
|
14489
|
+
}
|
|
14490
|
+
const browserCrypto = new CryptoOps(logger, performanceClient);
|
|
14491
|
+
const nativeInteractionClient = new NativeInteractionClient(config, browserStorage, browserCrypto, logger, eventHandler, config.system.navigationClient, apiId, performanceClient, nativeMessageHandler, accountId, nativeStorage, request.correlationId);
|
|
14492
|
+
const { userRequestState } = ProtocolUtils.parseRequestState(browserCrypto, request.state);
|
|
14493
|
+
return invokeAsync(nativeInteractionClient.acquireToken.bind(nativeInteractionClient), PerformanceEvents.NativeInteractionClientAcquireToken, logger, performanceClient, request.correlationId)({
|
|
14494
|
+
...request,
|
|
14495
|
+
state: userRequestState,
|
|
14496
|
+
prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
|
|
14497
|
+
});
|
|
14498
|
+
}
|
|
14499
|
+
/**
|
|
14500
|
+
* Response handler when server returns code on the /authorize request
|
|
14501
|
+
* @param request
|
|
14502
|
+
* @param response
|
|
14503
|
+
* @param codeVerifier
|
|
14504
|
+
* @param authClient
|
|
14505
|
+
* @param browserStorage
|
|
14506
|
+
* @param logger
|
|
14507
|
+
* @param performanceClient
|
|
14508
|
+
* @returns
|
|
14509
|
+
*/
|
|
14510
|
+
async function handleResponseCode(request, response, codeVerifier, apiId, config, authClient, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler) {
|
|
14511
|
+
// Remove throttle if it exists
|
|
14512
|
+
ThrottlingUtils.removeThrottle(browserStorage, config.auth.clientId, request);
|
|
14513
|
+
if (response.accountId) {
|
|
14514
|
+
return invokeAsync(handleResponsePlatformBroker, PerformanceEvents.HandleResponsePlatformBroker, logger, performanceClient, request.correlationId)(request, response.accountId, apiId, config, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler);
|
|
14515
|
+
}
|
|
14516
|
+
const authCodeRequest = {
|
|
14517
|
+
...request,
|
|
14518
|
+
code: response.code || "",
|
|
14519
|
+
codeVerifier: codeVerifier,
|
|
14520
|
+
};
|
|
14521
|
+
// Create popup interaction handler.
|
|
14522
|
+
const interactionHandler = new InteractionHandler(authClient, browserStorage, authCodeRequest, logger, performanceClient);
|
|
14523
|
+
// Handle response from hash string.
|
|
14524
|
+
const result = await invokeAsync(interactionHandler.handleCodeResponse.bind(interactionHandler), PerformanceEvents.HandleCodeResponse, logger, performanceClient, request.correlationId)(response, request);
|
|
14525
|
+
return result;
|
|
14526
|
+
}
|
|
14527
|
+
/**
|
|
14528
|
+
* Response handler when server returns ear_jwe on the /authorize request
|
|
14529
|
+
* @param request
|
|
14530
|
+
* @param response
|
|
14531
|
+
* @param apiId
|
|
14532
|
+
* @param config
|
|
14533
|
+
* @param authority
|
|
14534
|
+
* @param browserStorage
|
|
14535
|
+
* @param nativeStorage
|
|
14536
|
+
* @param eventHandler
|
|
14537
|
+
* @param logger
|
|
14538
|
+
* @param performanceClient
|
|
14539
|
+
* @param nativeMessageHandler
|
|
14540
|
+
* @returns
|
|
14541
|
+
*/
|
|
14542
|
+
async function handleResponseEAR(request, response, apiId, config, authority, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler) {
|
|
14543
|
+
// Remove throttle if it exists
|
|
14544
|
+
ThrottlingUtils.removeThrottle(browserStorage, config.auth.clientId, request);
|
|
14545
|
+
// Validate state & check response for errors
|
|
14546
|
+
validateAuthorizationResponse(response, request.state);
|
|
14547
|
+
if (!response.ear_jwe) {
|
|
14548
|
+
throw createBrowserAuthError(earJweEmpty);
|
|
14549
|
+
}
|
|
14550
|
+
if (!request.earJwk) {
|
|
14551
|
+
throw createBrowserAuthError(earJwkEmpty);
|
|
14552
|
+
}
|
|
14553
|
+
const decryptedData = JSON.parse(await invokeAsync(decryptEarResponse, PerformanceEvents.DecryptEarResponse, logger, performanceClient, request.correlationId)(request.earJwk, response.ear_jwe));
|
|
14554
|
+
if (decryptedData.accountId) {
|
|
14555
|
+
return invokeAsync(handleResponsePlatformBroker, PerformanceEvents.HandleResponsePlatformBroker, logger, performanceClient, request.correlationId)(request, decryptedData.accountId, apiId, config, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler);
|
|
14556
|
+
}
|
|
14557
|
+
const responseHandler = new ResponseHandler(config.auth.clientId, browserStorage, new CryptoOps(logger, performanceClient), logger, null, null, performanceClient);
|
|
14558
|
+
// Validate response. This function throws a server error if an error is returned by the server.
|
|
14559
|
+
responseHandler.validateTokenResponse(decryptedData);
|
|
14560
|
+
// Temporary until response handler is refactored to be more flow agnostic.
|
|
14561
|
+
const additionalData = {
|
|
14562
|
+
code: "",
|
|
14563
|
+
state: request.state,
|
|
14564
|
+
nonce: request.nonce,
|
|
14565
|
+
client_info: decryptedData.client_info,
|
|
14566
|
+
cloud_graph_host_name: decryptedData.cloud_graph_host_name,
|
|
14567
|
+
cloud_instance_host_name: decryptedData.cloud_instance_host_name,
|
|
14568
|
+
cloud_instance_name: decryptedData.cloud_instance_name,
|
|
14569
|
+
msgraph_host: decryptedData.msgraph_host,
|
|
14570
|
+
};
|
|
14571
|
+
return (await invokeAsync(responseHandler.handleServerTokenResponse.bind(responseHandler), PerformanceEvents.HandleServerTokenResponse, logger, performanceClient, request.correlationId)(decryptedData, authority, nowSeconds(), request, additionalData, undefined, undefined, undefined, undefined));
|
|
14496
14572
|
}
|
|
14497
14573
|
|
|
14498
14574
|
/*
|
|
@@ -14560,6 +14636,7 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14560
14636
|
// Properly sets this reference for the unload event.
|
|
14561
14637
|
this.unloadWindow = this.unloadWindow.bind(this);
|
|
14562
14638
|
this.nativeStorage = nativeStorageImpl;
|
|
14639
|
+
this.eventHandler = eventHandler;
|
|
14563
14640
|
}
|
|
14564
14641
|
/**
|
|
14565
14642
|
* Acquires tokens by opening a popup window to the /authorize endpoint of the authority
|
|
@@ -14635,11 +14712,7 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14635
14712
|
*/
|
|
14636
14713
|
async acquireTokenPopupAsync(request, popupParams, pkceCodes) {
|
|
14637
14714
|
this.logger.verbose("acquireTokenPopupAsync called");
|
|
14638
|
-
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenPopup);
|
|
14639
14715
|
const validRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, this.correlationId)(request, exports.InteractionType.Popup);
|
|
14640
|
-
const pkce = pkceCodes ||
|
|
14641
|
-
(await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, this.correlationId)(this.performanceClient, this.logger, this.correlationId));
|
|
14642
|
-
validRequest.codeChallenge = pkce.challenge;
|
|
14643
14716
|
/*
|
|
14644
14717
|
* Skip pre-connect for async popups to reduce time between user interaction and popup window creation to avoid
|
|
14645
14718
|
* popup from being blocked by browsers with shorter popup timers
|
|
@@ -14647,65 +14720,49 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14647
14720
|
if (popupParams.popup) {
|
|
14648
14721
|
preconnect(validRequest.authority);
|
|
14649
14722
|
}
|
|
14723
|
+
const isPlatformBroker = NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
|
|
14724
|
+
validRequest.platformBroker = isPlatformBroker;
|
|
14725
|
+
if (this.config.auth.protocolMode === ProtocolMode.EAR) {
|
|
14726
|
+
return this.executeEarFlow(validRequest, popupParams);
|
|
14727
|
+
}
|
|
14728
|
+
else {
|
|
14729
|
+
return this.executeCodeFlow(validRequest, popupParams, pkceCodes);
|
|
14730
|
+
}
|
|
14731
|
+
}
|
|
14732
|
+
/**
|
|
14733
|
+
* Executes auth code + PKCE flow
|
|
14734
|
+
* @param request
|
|
14735
|
+
* @param popupParams
|
|
14736
|
+
* @param pkceCodes
|
|
14737
|
+
* @returns
|
|
14738
|
+
*/
|
|
14739
|
+
async executeCodeFlow(request, popupParams, pkceCodes) {
|
|
14740
|
+
const correlationId = request.correlationId;
|
|
14741
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenPopup);
|
|
14742
|
+
const pkce = pkceCodes ||
|
|
14743
|
+
(await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, correlationId)(this.performanceClient, this.logger, correlationId));
|
|
14744
|
+
const popupRequest = {
|
|
14745
|
+
...request,
|
|
14746
|
+
codeChallenge: pkce.challenge,
|
|
14747
|
+
};
|
|
14650
14748
|
try {
|
|
14651
14749
|
// Initialize the client
|
|
14652
|
-
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient,
|
|
14750
|
+
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, correlationId)({
|
|
14653
14751
|
serverTelemetryManager,
|
|
14654
|
-
requestAuthority:
|
|
14655
|
-
requestAzureCloudOptions:
|
|
14656
|
-
requestExtraQueryParameters:
|
|
14657
|
-
account:
|
|
14752
|
+
requestAuthority: popupRequest.authority,
|
|
14753
|
+
requestAzureCloudOptions: popupRequest.azureCloudOptions,
|
|
14754
|
+
requestExtraQueryParameters: popupRequest.extraQueryParameters,
|
|
14755
|
+
account: popupRequest.account,
|
|
14658
14756
|
});
|
|
14659
|
-
const isPlatformBroker = NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
|
|
14660
|
-
// Start measurement for server calls with native brokering enabled
|
|
14661
|
-
let fetchNativeAccountIdMeasurement;
|
|
14662
|
-
if (isPlatformBroker) {
|
|
14663
|
-
fetchNativeAccountIdMeasurement =
|
|
14664
|
-
this.performanceClient.startMeasurement(PerformanceEvents.FetchAccountIdWithNativeBroker, request.correlationId);
|
|
14665
|
-
}
|
|
14666
14757
|
// Create acquire token url.
|
|
14667
|
-
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient,
|
|
14668
|
-
...validRequest,
|
|
14669
|
-
platformBroker: isPlatformBroker,
|
|
14670
|
-
}, this.logger, this.performanceClient);
|
|
14758
|
+
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, correlationId)(this.config, authClient.authority, popupRequest, this.logger, this.performanceClient);
|
|
14671
14759
|
// Show the UI once the url has been created. Get the window handle for the popup.
|
|
14672
14760
|
const popupWindow = this.initiateAuthRequest(navigateUrl, popupParams);
|
|
14673
14761
|
this.eventHandler.emitEvent(EventType.POPUP_OPENED, exports.InteractionType.Popup, { popupWindow }, null);
|
|
14674
14762
|
// Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
|
|
14675
14763
|
const responseString = await this.monitorPopupForHash(popupWindow, popupParams.popupWindowParent);
|
|
14676
14764
|
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, this.correlationId)(responseString, this.config.auth.OIDCOptions.serverResponseType, this.logger);
|
|
14677
|
-
|
|
14678
|
-
ThrottlingUtils.removeThrottle(this.browserStorage, this.config.auth.clientId, validRequest);
|
|
14679
|
-
if (serverParams.accountId) {
|
|
14680
|
-
this.logger.verbose("Account id found in hash, calling WAM for token");
|
|
14681
|
-
// end measurement for server call with native brokering enabled
|
|
14682
|
-
if (fetchNativeAccountIdMeasurement) {
|
|
14683
|
-
fetchNativeAccountIdMeasurement.end({
|
|
14684
|
-
success: true,
|
|
14685
|
-
isNativeBroker: true,
|
|
14686
|
-
});
|
|
14687
|
-
}
|
|
14688
|
-
if (!this.nativeMessageHandler) {
|
|
14689
|
-
throw createBrowserAuthError(nativeConnectionNotEstablished);
|
|
14690
|
-
}
|
|
14691
|
-
const nativeInteractionClient = new NativeInteractionClient(this.config, this.browserStorage, this.browserCrypto, this.logger, this.eventHandler, this.navigationClient, ApiId.acquireTokenPopup, this.performanceClient, this.nativeMessageHandler, serverParams.accountId, this.nativeStorage, validRequest.correlationId);
|
|
14692
|
-
const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, validRequest.state);
|
|
14693
|
-
return await nativeInteractionClient.acquireToken({
|
|
14694
|
-
...validRequest,
|
|
14695
|
-
state: userRequestState,
|
|
14696
|
-
prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
|
|
14697
|
-
});
|
|
14698
|
-
}
|
|
14699
|
-
const authCodeRequest = {
|
|
14700
|
-
...validRequest,
|
|
14701
|
-
code: serverParams.code || "",
|
|
14702
|
-
codeVerifier: pkce.verifier,
|
|
14703
|
-
};
|
|
14704
|
-
// Create popup interaction handler.
|
|
14705
|
-
const interactionHandler = new InteractionHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.performanceClient);
|
|
14706
|
-
// Handle response from hash string.
|
|
14707
|
-
const result = await interactionHandler.handleCodeResponse(serverParams, validRequest);
|
|
14708
|
-
return result;
|
|
14765
|
+
return await invokeAsync(handleResponseCode, PerformanceEvents.HandleResponseCode, this.logger, this.performanceClient, correlationId)(request, serverParams, pkce.verifier, ApiId.acquireTokenPopup, this.config, authClient, this.browserStorage, this.nativeStorage, this.eventHandler, this.logger, this.performanceClient, this.nativeMessageHandler);
|
|
14709
14766
|
}
|
|
14710
14767
|
catch (e) {
|
|
14711
14768
|
// Close the synchronous popup if an error is thrown before the window unload event is registered
|
|
@@ -14717,6 +14774,32 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14717
14774
|
throw e;
|
|
14718
14775
|
}
|
|
14719
14776
|
}
|
|
14777
|
+
/**
|
|
14778
|
+
* Executes EAR flow
|
|
14779
|
+
* @param request
|
|
14780
|
+
*/
|
|
14781
|
+
async executeEarFlow(request, popupParams) {
|
|
14782
|
+
const correlationId = request.correlationId;
|
|
14783
|
+
// Get the frame handle for the silent request
|
|
14784
|
+
const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, correlationId)({
|
|
14785
|
+
requestAuthority: request.authority,
|
|
14786
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
14787
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
14788
|
+
account: request.account,
|
|
14789
|
+
});
|
|
14790
|
+
const earJwk = await invokeAsync(generateEarKey, PerformanceEvents.GenerateEarKey, this.logger, this.performanceClient, correlationId)();
|
|
14791
|
+
const popupRequest = {
|
|
14792
|
+
...request,
|
|
14793
|
+
earJwk: earJwk,
|
|
14794
|
+
};
|
|
14795
|
+
const popupWindow = popupParams.popup || this.openPopup("about:blank", popupParams);
|
|
14796
|
+
const form = await getEARForm(popupWindow.document, this.config, discoveredAuthority, popupRequest, this.logger, this.performanceClient);
|
|
14797
|
+
form.submit();
|
|
14798
|
+
// Monitor the popup for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
|
|
14799
|
+
const responseString = await invokeAsync(this.monitorPopupForHash.bind(this), PerformanceEvents.SilentHandlerMonitorIframeForHash, this.logger, this.performanceClient, correlationId)(popupWindow, popupParams.popupWindowParent);
|
|
14800
|
+
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, this.correlationId)(responseString, this.config.auth.OIDCOptions.serverResponseType, this.logger);
|
|
14801
|
+
return invokeAsync(handleResponseEAR, PerformanceEvents.HandleResponseEar, this.logger, this.performanceClient, correlationId)(popupRequest, serverParams, ApiId.acquireTokenPopup, this.config, discoveredAuthority, this.browserStorage, this.nativeStorage, this.eventHandler, this.logger, this.performanceClient, this.nativeMessageHandler);
|
|
14802
|
+
}
|
|
14720
14803
|
/**
|
|
14721
14804
|
*
|
|
14722
14805
|
* @param validRequest
|
|
@@ -14792,7 +14875,6 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14792
14875
|
e.setCorrelationId(this.correlationId);
|
|
14793
14876
|
serverTelemetryManager.cacheFailedRequest(e);
|
|
14794
14877
|
}
|
|
14795
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
14796
14878
|
this.eventHandler.emitEvent(EventType.LOGOUT_FAILURE, exports.InteractionType.Popup, null, e);
|
|
14797
14879
|
this.eventHandler.emitEvent(EventType.LOGOUT_END, exports.InteractionType.Popup);
|
|
14798
14880
|
throw e;
|
|
@@ -14904,7 +14986,6 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14904
14986
|
}
|
|
14905
14987
|
catch (e) {
|
|
14906
14988
|
this.logger.error("error opening popup " + e.message);
|
|
14907
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
14908
14989
|
throw createBrowserAuthError(popupWindowError);
|
|
14909
14990
|
}
|
|
14910
14991
|
}
|
|
@@ -14962,7 +15043,6 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14962
15043
|
* Event callback to unload main window.
|
|
14963
15044
|
*/
|
|
14964
15045
|
unloadWindow(e) {
|
|
14965
|
-
this.browserStorage.cleanRequestByInteractionType(exports.InteractionType.Popup);
|
|
14966
15046
|
if (this.currentWindow) {
|
|
14967
15047
|
this.currentWindow.close();
|
|
14968
15048
|
}
|
|
@@ -14978,8 +15058,6 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14978
15058
|
popupWindow.close();
|
|
14979
15059
|
// Remove window unload function
|
|
14980
15060
|
popupWindowParent.removeEventListener("beforeunload", this.unloadWindow);
|
|
14981
|
-
// Interaction is completed - remove interaction status.
|
|
14982
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
14983
15061
|
}
|
|
14984
15062
|
/**
|
|
14985
15063
|
* Generates the name for the popup based on the client id and request
|
|
@@ -15000,141 +15078,6 @@ class PopupClient extends StandardInteractionClient {
|
|
|
15000
15078
|
}
|
|
15001
15079
|
}
|
|
15002
15080
|
|
|
15003
|
-
/*
|
|
15004
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
15005
|
-
* Licensed under the MIT License.
|
|
15006
|
-
*/
|
|
15007
|
-
class RedirectHandler {
|
|
15008
|
-
constructor(authCodeModule, storageImpl, authCodeRequest, logger, performanceClient) {
|
|
15009
|
-
this.authModule = authCodeModule;
|
|
15010
|
-
this.browserStorage = storageImpl;
|
|
15011
|
-
this.authCodeRequest = authCodeRequest;
|
|
15012
|
-
this.logger = logger;
|
|
15013
|
-
this.performanceClient = performanceClient;
|
|
15014
|
-
}
|
|
15015
|
-
/**
|
|
15016
|
-
* Redirects window to given URL.
|
|
15017
|
-
* @param urlNavigate
|
|
15018
|
-
*/
|
|
15019
|
-
async initiateAuthRequest(requestUrl, params) {
|
|
15020
|
-
this.logger.verbose("RedirectHandler.initiateAuthRequest called");
|
|
15021
|
-
// Navigate if valid URL
|
|
15022
|
-
if (requestUrl) {
|
|
15023
|
-
// Cache start page, returns to this page after redirectUri if navigateToLoginRequestUrl is true
|
|
15024
|
-
if (params.redirectStartPage) {
|
|
15025
|
-
this.logger.verbose("RedirectHandler.initiateAuthRequest: redirectStartPage set, caching start page");
|
|
15026
|
-
this.browserStorage.setTemporaryCache(TemporaryCacheKeys.ORIGIN_URI, params.redirectStartPage, true);
|
|
15027
|
-
}
|
|
15028
|
-
// Set interaction status in the library.
|
|
15029
|
-
this.browserStorage.setTemporaryCache(TemporaryCacheKeys.CORRELATION_ID, this.authCodeRequest.correlationId, true);
|
|
15030
|
-
this.browserStorage.cacheCodeRequest(this.authCodeRequest);
|
|
15031
|
-
this.logger.infoPii(`RedirectHandler.initiateAuthRequest: Navigate to: ${requestUrl}`);
|
|
15032
|
-
const navigationOptions = {
|
|
15033
|
-
apiId: ApiId.acquireTokenRedirect,
|
|
15034
|
-
timeout: params.redirectTimeout,
|
|
15035
|
-
noHistory: false,
|
|
15036
|
-
};
|
|
15037
|
-
// If onRedirectNavigate is implemented, invoke it and provide requestUrl
|
|
15038
|
-
if (typeof params.onRedirectNavigate === "function") {
|
|
15039
|
-
this.logger.verbose("RedirectHandler.initiateAuthRequest: Invoking onRedirectNavigate callback");
|
|
15040
|
-
const navigate = params.onRedirectNavigate(requestUrl);
|
|
15041
|
-
// Returning false from onRedirectNavigate will stop navigation
|
|
15042
|
-
if (navigate !== false) {
|
|
15043
|
-
this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate did not return false, navigating");
|
|
15044
|
-
await params.navigationClient.navigateExternal(requestUrl, navigationOptions);
|
|
15045
|
-
return;
|
|
15046
|
-
}
|
|
15047
|
-
else {
|
|
15048
|
-
this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate returned false, stopping navigation");
|
|
15049
|
-
return;
|
|
15050
|
-
}
|
|
15051
|
-
}
|
|
15052
|
-
else {
|
|
15053
|
-
// Navigate window to request URL
|
|
15054
|
-
this.logger.verbose("RedirectHandler.initiateAuthRequest: Navigating window to navigate url");
|
|
15055
|
-
await params.navigationClient.navigateExternal(requestUrl, navigationOptions);
|
|
15056
|
-
return;
|
|
15057
|
-
}
|
|
15058
|
-
}
|
|
15059
|
-
else {
|
|
15060
|
-
// Throw error if request URL is empty.
|
|
15061
|
-
this.logger.info("RedirectHandler.initiateAuthRequest: Navigate url is empty");
|
|
15062
|
-
throw createBrowserAuthError(emptyNavigateUri);
|
|
15063
|
-
}
|
|
15064
|
-
}
|
|
15065
|
-
/**
|
|
15066
|
-
* Handle authorization code response in the window.
|
|
15067
|
-
* @param hash
|
|
15068
|
-
*/
|
|
15069
|
-
async handleCodeResponse(response, state) {
|
|
15070
|
-
this.logger.verbose("RedirectHandler.handleCodeResponse called");
|
|
15071
|
-
// Interaction is completed - remove interaction status.
|
|
15072
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
15073
|
-
// Handle code response.
|
|
15074
|
-
const stateKey = this.browserStorage.generateStateKey(state);
|
|
15075
|
-
const requestState = this.browserStorage.getTemporaryCache(stateKey);
|
|
15076
|
-
if (!requestState) {
|
|
15077
|
-
throw createClientAuthError(stateNotFound, "Cached State");
|
|
15078
|
-
}
|
|
15079
|
-
let authCodeResponse;
|
|
15080
|
-
try {
|
|
15081
|
-
authCodeResponse = getAuthorizationCodePayload(response, requestState);
|
|
15082
|
-
}
|
|
15083
|
-
catch (e) {
|
|
15084
|
-
if (e instanceof ServerError &&
|
|
15085
|
-
e.subError === userCancelled) {
|
|
15086
|
-
// Translate server error caused by user closing native prompt to corresponding first class MSAL error
|
|
15087
|
-
throw createBrowserAuthError(userCancelled);
|
|
15088
|
-
}
|
|
15089
|
-
else {
|
|
15090
|
-
throw e;
|
|
15091
|
-
}
|
|
15092
|
-
}
|
|
15093
|
-
// Get cached items
|
|
15094
|
-
const nonceKey = this.browserStorage.generateNonceKey(requestState);
|
|
15095
|
-
const cachedNonce = this.browserStorage.getTemporaryCache(nonceKey);
|
|
15096
|
-
// Assign code to request
|
|
15097
|
-
this.authCodeRequest.code = authCodeResponse.code;
|
|
15098
|
-
// Check for new cloud instance
|
|
15099
|
-
if (authCodeResponse.cloud_instance_host_name) {
|
|
15100
|
-
await invokeAsync(this.authModule.updateAuthority.bind(this.authModule), PerformanceEvents.UpdateTokenEndpointAuthority, this.logger, this.performanceClient, this.authCodeRequest.correlationId)(authCodeResponse.cloud_instance_host_name, this.authCodeRequest.correlationId);
|
|
15101
|
-
}
|
|
15102
|
-
authCodeResponse.nonce = cachedNonce || undefined;
|
|
15103
|
-
authCodeResponse.state = requestState;
|
|
15104
|
-
// Add CCS parameters if available
|
|
15105
|
-
if (authCodeResponse.client_info) {
|
|
15106
|
-
this.authCodeRequest.clientInfo = authCodeResponse.client_info;
|
|
15107
|
-
}
|
|
15108
|
-
else {
|
|
15109
|
-
const cachedCcsCred = this.checkCcsCredentials();
|
|
15110
|
-
if (cachedCcsCred) {
|
|
15111
|
-
this.authCodeRequest.ccsCredential = cachedCcsCred;
|
|
15112
|
-
}
|
|
15113
|
-
}
|
|
15114
|
-
// Acquire token with retrieved code.
|
|
15115
|
-
const tokenResponse = (await this.authModule.acquireToken(this.authCodeRequest, authCodeResponse));
|
|
15116
|
-
this.browserStorage.cleanRequestByState(state);
|
|
15117
|
-
return tokenResponse;
|
|
15118
|
-
}
|
|
15119
|
-
/**
|
|
15120
|
-
* Looks up ccs creds in the cache
|
|
15121
|
-
*/
|
|
15122
|
-
checkCcsCredentials() {
|
|
15123
|
-
// Look up ccs credential in temp cache
|
|
15124
|
-
const cachedCcsCred = this.browserStorage.getTemporaryCache(TemporaryCacheKeys.CCS_CREDENTIAL, true);
|
|
15125
|
-
if (cachedCcsCred) {
|
|
15126
|
-
try {
|
|
15127
|
-
return JSON.parse(cachedCcsCred);
|
|
15128
|
-
}
|
|
15129
|
-
catch (e) {
|
|
15130
|
-
this.authModule.logger.error("Cache credential could not be parsed");
|
|
15131
|
-
this.authModule.logger.errorPii(`Cache credential could not be parsed: ${cachedCcsCred}`);
|
|
15132
|
-
}
|
|
15133
|
-
}
|
|
15134
|
-
return null;
|
|
15135
|
-
}
|
|
15136
|
-
}
|
|
15137
|
-
|
|
15138
15081
|
/*
|
|
15139
15082
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
15140
15083
|
* Licensed under the MIT License.
|
|
@@ -15162,62 +15105,96 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15162
15105
|
*/
|
|
15163
15106
|
async acquireToken(request) {
|
|
15164
15107
|
const validRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, this.correlationId)(request, exports.InteractionType.Redirect);
|
|
15165
|
-
|
|
15166
|
-
|
|
15167
|
-
this.browserStorage.updateCacheEntries(validRequest.state, validRequest.nonce, validRequest.authority, validRequest.loginHint || "", validRequest.account || null);
|
|
15168
|
-
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenRedirect);
|
|
15108
|
+
validRequest.platformBroker =
|
|
15109
|
+
NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
|
|
15169
15110
|
const handleBackButton = (event) => {
|
|
15170
15111
|
// Clear temporary cache if the back button is clicked during the redirect flow.
|
|
15171
15112
|
if (event.persisted) {
|
|
15172
15113
|
this.logger.verbose("Page was restored from back/forward cache. Clearing temporary cache.");
|
|
15173
|
-
this.browserStorage.
|
|
15114
|
+
this.browserStorage.resetRequestCache();
|
|
15174
15115
|
this.eventHandler.emitEvent(EventType.RESTORE_FROM_BFCACHE, exports.InteractionType.Redirect);
|
|
15175
15116
|
}
|
|
15176
15117
|
};
|
|
15118
|
+
const redirectStartPage = this.getRedirectStartPage(request.redirectStartPage);
|
|
15119
|
+
this.logger.verbosePii(`Redirect start page: ${redirectStartPage}`);
|
|
15120
|
+
// Cache start page, returns to this page after redirectUri if navigateToLoginRequestUrl is true
|
|
15121
|
+
this.browserStorage.setTemporaryCache(TemporaryCacheKeys.ORIGIN_URI, redirectStartPage, true);
|
|
15122
|
+
// Clear temporary cache if the back button is clicked during the redirect flow.
|
|
15123
|
+
window.addEventListener("pageshow", handleBackButton);
|
|
15124
|
+
try {
|
|
15125
|
+
if (this.config.auth.protocolMode === ProtocolMode.EAR) {
|
|
15126
|
+
await this.executeEarFlow(validRequest);
|
|
15127
|
+
}
|
|
15128
|
+
else {
|
|
15129
|
+
await this.executeCodeFlow(validRequest, request.onRedirectNavigate);
|
|
15130
|
+
}
|
|
15131
|
+
}
|
|
15132
|
+
catch (e) {
|
|
15133
|
+
if (e instanceof AuthError) {
|
|
15134
|
+
e.setCorrelationId(this.correlationId);
|
|
15135
|
+
}
|
|
15136
|
+
window.removeEventListener("pageshow", handleBackButton);
|
|
15137
|
+
throw e;
|
|
15138
|
+
}
|
|
15139
|
+
}
|
|
15140
|
+
/**
|
|
15141
|
+
* Executes auth code + PKCE flow
|
|
15142
|
+
* @param request
|
|
15143
|
+
* @returns
|
|
15144
|
+
*/
|
|
15145
|
+
async executeCodeFlow(request, onRedirectNavigate) {
|
|
15146
|
+
const correlationId = request.correlationId;
|
|
15147
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenRedirect);
|
|
15148
|
+
const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, correlationId)(this.performanceClient, this.logger, correlationId);
|
|
15149
|
+
const redirectRequest = {
|
|
15150
|
+
...request,
|
|
15151
|
+
codeChallenge: pkceCodes.challenge,
|
|
15152
|
+
};
|
|
15153
|
+
this.browserStorage.cacheAuthorizeRequest(redirectRequest, pkceCodes.verifier);
|
|
15177
15154
|
try {
|
|
15178
15155
|
// Initialize the client
|
|
15179
15156
|
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)({
|
|
15180
15157
|
serverTelemetryManager,
|
|
15181
|
-
requestAuthority:
|
|
15182
|
-
requestAzureCloudOptions:
|
|
15183
|
-
requestExtraQueryParameters:
|
|
15184
|
-
account:
|
|
15158
|
+
requestAuthority: redirectRequest.authority,
|
|
15159
|
+
requestAzureCloudOptions: redirectRequest.azureCloudOptions,
|
|
15160
|
+
requestExtraQueryParameters: redirectRequest.extraQueryParameters,
|
|
15161
|
+
account: redirectRequest.account,
|
|
15185
15162
|
});
|
|
15186
|
-
const authCodeRequest = {
|
|
15187
|
-
...validRequest,
|
|
15188
|
-
code: "",
|
|
15189
|
-
codeVerifier: pkceCodes.verifier,
|
|
15190
|
-
};
|
|
15191
|
-
// Create redirect interaction handler.
|
|
15192
|
-
const interactionHandler = new RedirectHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.performanceClient);
|
|
15193
15163
|
// Create acquire token url.
|
|
15194
|
-
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient,
|
|
15195
|
-
...validRequest,
|
|
15196
|
-
platformBroker: NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme),
|
|
15197
|
-
}, this.logger, this.performanceClient);
|
|
15198
|
-
const redirectStartPage = this.getRedirectStartPage(request.redirectStartPage);
|
|
15199
|
-
this.logger.verbosePii(`Redirect start page: ${redirectStartPage}`);
|
|
15200
|
-
// Clear temporary cache if the back button is clicked during the redirect flow.
|
|
15201
|
-
window.addEventListener("pageshow", handleBackButton);
|
|
15164
|
+
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, request.correlationId)(this.config, authClient.authority, redirectRequest, this.logger, this.performanceClient);
|
|
15202
15165
|
// Show the UI once the url has been created. Response will come back in the hash, which will be handled in the handleRedirectCallback function.
|
|
15203
|
-
return await
|
|
15204
|
-
navigationClient: this.navigationClient,
|
|
15205
|
-
redirectTimeout: this.config.system.redirectNavigationTimeout,
|
|
15206
|
-
redirectStartPage: redirectStartPage,
|
|
15207
|
-
onRedirectNavigate: request.onRedirectNavigate ||
|
|
15208
|
-
this.config.auth.onRedirectNavigate,
|
|
15209
|
-
});
|
|
15166
|
+
return await this.initiateAuthRequest(navigateUrl, onRedirectNavigate);
|
|
15210
15167
|
}
|
|
15211
15168
|
catch (e) {
|
|
15212
15169
|
if (e instanceof AuthError) {
|
|
15213
15170
|
e.setCorrelationId(this.correlationId);
|
|
15214
15171
|
serverTelemetryManager.cacheFailedRequest(e);
|
|
15215
15172
|
}
|
|
15216
|
-
window.removeEventListener("pageshow", handleBackButton);
|
|
15217
|
-
this.browserStorage.cleanRequestByState(validRequest.state);
|
|
15218
15173
|
throw e;
|
|
15219
15174
|
}
|
|
15220
15175
|
}
|
|
15176
|
+
/**
|
|
15177
|
+
* Executes EAR flow
|
|
15178
|
+
* @param request
|
|
15179
|
+
*/
|
|
15180
|
+
async executeEarFlow(request) {
|
|
15181
|
+
const correlationId = request.correlationId;
|
|
15182
|
+
// Get the frame handle for the silent request
|
|
15183
|
+
const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, correlationId)({
|
|
15184
|
+
requestAuthority: request.authority,
|
|
15185
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
15186
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
15187
|
+
account: request.account,
|
|
15188
|
+
});
|
|
15189
|
+
const earJwk = await invokeAsync(generateEarKey, PerformanceEvents.GenerateEarKey, this.logger, this.performanceClient, correlationId)();
|
|
15190
|
+
const redirectRequest = {
|
|
15191
|
+
...request,
|
|
15192
|
+
earJwk: earJwk,
|
|
15193
|
+
};
|
|
15194
|
+
this.browserStorage.cacheAuthorizeRequest(redirectRequest);
|
|
15195
|
+
const form = await getEARForm(document, this.config, discoveredAuthority, redirectRequest, this.logger, this.performanceClient);
|
|
15196
|
+
form.submit();
|
|
15197
|
+
}
|
|
15221
15198
|
/**
|
|
15222
15199
|
* Checks if navigateToLoginRequestUrl is set, and:
|
|
15223
15200
|
* - if true, performs logic to cache and navigate
|
|
@@ -15225,18 +15202,14 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15225
15202
|
* @param hash {string} url hash
|
|
15226
15203
|
* @param parentMeasurement {InProgressPerformanceEvent} parent measurement
|
|
15227
15204
|
*/
|
|
15228
|
-
async handleRedirectPromise(hash = "", parentMeasurement) {
|
|
15205
|
+
async handleRedirectPromise(hash = "", request, pkceVerifier, parentMeasurement) {
|
|
15229
15206
|
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.handleRedirectPromise);
|
|
15230
15207
|
try {
|
|
15231
|
-
if (!this.browserStorage.isInteractionInProgress(true)) {
|
|
15232
|
-
this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
|
|
15233
|
-
return null;
|
|
15234
|
-
}
|
|
15235
15208
|
const [serverParams, responseString] = this.getRedirectResponse(hash || "");
|
|
15236
15209
|
if (!serverParams) {
|
|
15237
15210
|
// Not a recognized server response hash or hash not associated with a redirect request
|
|
15238
15211
|
this.logger.info("handleRedirectPromise did not detect a response as a result of a redirect. Cleaning temporary cache.");
|
|
15239
|
-
this.browserStorage.
|
|
15212
|
+
this.browserStorage.resetRequestCache();
|
|
15240
15213
|
// Do not instrument "no_server_response" if user clicked back button
|
|
15241
15214
|
if (getNavigationType() !== "back_forward") {
|
|
15242
15215
|
parentMeasurement.event.errorCode = "no_server_response";
|
|
@@ -15258,12 +15231,12 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15258
15231
|
// Replace current hash with non-msal hash, if present
|
|
15259
15232
|
replaceHash(loginRequestUrl);
|
|
15260
15233
|
}
|
|
15261
|
-
const handleHashResult = await this.handleResponse(serverParams, serverTelemetryManager);
|
|
15234
|
+
const handleHashResult = await this.handleResponse(serverParams, request, pkceVerifier, serverTelemetryManager);
|
|
15262
15235
|
return handleHashResult;
|
|
15263
15236
|
}
|
|
15264
15237
|
else if (!this.config.auth.navigateToLoginRequestUrl) {
|
|
15265
15238
|
this.logger.verbose("NavigateToLoginRequestUrl set to false, handling response");
|
|
15266
|
-
return await this.handleResponse(serverParams, serverTelemetryManager);
|
|
15239
|
+
return await this.handleResponse(serverParams, request, pkceVerifier, serverTelemetryManager);
|
|
15267
15240
|
}
|
|
15268
15241
|
else if (!isInIframe() ||
|
|
15269
15242
|
this.config.system.allowRedirectInIframe) {
|
|
@@ -15299,7 +15272,7 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15299
15272
|
}
|
|
15300
15273
|
// If navigateInternal implementation returns false, handle the hash now
|
|
15301
15274
|
if (!processHashOnRedirect) {
|
|
15302
|
-
return await this.handleResponse(serverParams, serverTelemetryManager);
|
|
15275
|
+
return await this.handleResponse(serverParams, request, pkceVerifier, serverTelemetryManager);
|
|
15303
15276
|
}
|
|
15304
15277
|
}
|
|
15305
15278
|
return null;
|
|
@@ -15309,7 +15282,6 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15309
15282
|
e.setCorrelationId(this.correlationId);
|
|
15310
15283
|
serverTelemetryManager.cacheFailedRequest(e);
|
|
15311
15284
|
}
|
|
15312
|
-
this.browserStorage.cleanRequestByInteractionType(exports.InteractionType.Redirect);
|
|
15313
15285
|
throw e;
|
|
15314
15286
|
}
|
|
15315
15287
|
}
|
|
@@ -15362,39 +15334,67 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15362
15334
|
* @param hash
|
|
15363
15335
|
* @param state
|
|
15364
15336
|
*/
|
|
15365
|
-
async handleResponse(serverParams, serverTelemetryManager) {
|
|
15337
|
+
async handleResponse(serverParams, request, codeVerifier, serverTelemetryManager) {
|
|
15366
15338
|
const state = serverParams.state;
|
|
15367
15339
|
if (!state) {
|
|
15368
15340
|
throw createBrowserAuthError(noStateInHash);
|
|
15369
15341
|
}
|
|
15370
|
-
|
|
15371
|
-
|
|
15372
|
-
|
|
15373
|
-
|
|
15374
|
-
|
|
15375
|
-
|
|
15376
|
-
}
|
|
15377
|
-
const nativeInteractionClient = new NativeInteractionClient(this.config, this.browserStorage, this.browserCrypto, this.logger, this.eventHandler, this.navigationClient, ApiId.acquireTokenPopup, this.performanceClient, this.nativeMessageHandler, serverParams.accountId, this.nativeStorage, cachedRequest.correlationId);
|
|
15378
|
-
const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, state);
|
|
15379
|
-
return nativeInteractionClient
|
|
15380
|
-
.acquireToken({
|
|
15381
|
-
...cachedRequest,
|
|
15382
|
-
state: userRequestState,
|
|
15383
|
-
prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
|
|
15384
|
-
})
|
|
15385
|
-
.finally(() => {
|
|
15386
|
-
this.browserStorage.cleanRequestByState(state);
|
|
15342
|
+
if (serverParams.ear_jwe) {
|
|
15343
|
+
const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, request.correlationId)({
|
|
15344
|
+
requestAuthority: request.authority,
|
|
15345
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
15346
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
15347
|
+
account: request.account,
|
|
15387
15348
|
});
|
|
15349
|
+
return invokeAsync(handleResponseEAR, PerformanceEvents.HandleResponseEar, this.logger, this.performanceClient, request.correlationId)(request, serverParams, ApiId.acquireTokenRedirect, this.config, discoveredAuthority, this.browserStorage, this.nativeStorage, this.eventHandler, this.logger, this.performanceClient, this.nativeMessageHandler);
|
|
15350
|
+
}
|
|
15351
|
+
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)({ serverTelemetryManager, requestAuthority: request.authority });
|
|
15352
|
+
return invokeAsync(handleResponseCode, PerformanceEvents.HandleResponseCode, this.logger, this.performanceClient, request.correlationId)(request, serverParams, codeVerifier, ApiId.acquireTokenRedirect, this.config, authClient, this.browserStorage, this.nativeStorage, this.eventHandler, this.logger, this.performanceClient, this.nativeMessageHandler);
|
|
15353
|
+
}
|
|
15354
|
+
/**
|
|
15355
|
+
* Redirects window to given URL.
|
|
15356
|
+
* @param urlNavigate
|
|
15357
|
+
* @param onRedirectNavigateRequest - onRedirectNavigate callback provided on the request
|
|
15358
|
+
*/
|
|
15359
|
+
async initiateAuthRequest(requestUrl, onRedirectNavigateRequest) {
|
|
15360
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest called");
|
|
15361
|
+
// Navigate if valid URL
|
|
15362
|
+
if (requestUrl) {
|
|
15363
|
+
this.logger.infoPii(`RedirectHandler.initiateAuthRequest: Navigate to: ${requestUrl}`);
|
|
15364
|
+
const navigationOptions = {
|
|
15365
|
+
apiId: ApiId.acquireTokenRedirect,
|
|
15366
|
+
timeout: this.config.system.redirectNavigationTimeout,
|
|
15367
|
+
noHistory: false,
|
|
15368
|
+
};
|
|
15369
|
+
const onRedirectNavigate = onRedirectNavigateRequest ||
|
|
15370
|
+
this.config.auth.onRedirectNavigate;
|
|
15371
|
+
// If onRedirectNavigate is implemented, invoke it and provide requestUrl
|
|
15372
|
+
if (typeof onRedirectNavigate === "function") {
|
|
15373
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest: Invoking onRedirectNavigate callback");
|
|
15374
|
+
const navigate = onRedirectNavigate(requestUrl);
|
|
15375
|
+
// Returning false from onRedirectNavigate will stop navigation
|
|
15376
|
+
if (navigate !== false) {
|
|
15377
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate did not return false, navigating");
|
|
15378
|
+
await this.navigationClient.navigateExternal(requestUrl, navigationOptions);
|
|
15379
|
+
return;
|
|
15380
|
+
}
|
|
15381
|
+
else {
|
|
15382
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate returned false, stopping navigation");
|
|
15383
|
+
return;
|
|
15384
|
+
}
|
|
15385
|
+
}
|
|
15386
|
+
else {
|
|
15387
|
+
// Navigate window to request URL
|
|
15388
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest: Navigating window to navigate url");
|
|
15389
|
+
await this.navigationClient.navigateExternal(requestUrl, navigationOptions);
|
|
15390
|
+
return;
|
|
15391
|
+
}
|
|
15388
15392
|
}
|
|
15389
|
-
|
|
15390
|
-
|
|
15391
|
-
|
|
15392
|
-
throw createBrowserAuthError(
|
|
15393
|
+
else {
|
|
15394
|
+
// Throw error if request URL is empty.
|
|
15395
|
+
this.logger.info("RedirectHandler.initiateAuthRequest: Navigate url is empty");
|
|
15396
|
+
throw createBrowserAuthError(emptyNavigateUri);
|
|
15393
15397
|
}
|
|
15394
|
-
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)({ serverTelemetryManager, requestAuthority: currentAuthority });
|
|
15395
|
-
ThrottlingUtils.removeThrottle(this.browserStorage, this.config.auth.clientId, cachedRequest);
|
|
15396
|
-
const interactionHandler = new RedirectHandler(authClient, this.browserStorage, cachedRequest, this.logger, this.performanceClient);
|
|
15397
|
-
return interactionHandler.handleCodeResponse(serverParams, state);
|
|
15398
15398
|
}
|
|
15399
15399
|
/**
|
|
15400
15400
|
* Use to log out the current user, and redirect the user to the postLogoutRedirectUri.
|
|
@@ -15493,7 +15493,7 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15493
15493
|
* @param urlNavigate
|
|
15494
15494
|
* @param userRequestScopes
|
|
15495
15495
|
*/
|
|
15496
|
-
async function
|
|
15496
|
+
async function initiateCodeRequest(requestUrl, performanceClient, logger, correlationId, navigateFrameWait) {
|
|
15497
15497
|
performanceClient.addQueueMeasurement(PerformanceEvents.SilentHandlerInitiateAuthRequest, correlationId);
|
|
15498
15498
|
if (!requestUrl) {
|
|
15499
15499
|
// Throw error if request URL is empty.
|
|
@@ -15505,6 +15505,15 @@ async function initiateAuthRequest(requestUrl, performanceClient, logger, correl
|
|
|
15505
15505
|
}
|
|
15506
15506
|
return invoke(loadFrameSync, PerformanceEvents.SilentHandlerLoadFrameSync, logger, performanceClient, correlationId)(requestUrl);
|
|
15507
15507
|
}
|
|
15508
|
+
async function initiateEarRequest(config, authority, request, logger, performanceClient) {
|
|
15509
|
+
const frame = createHiddenIframe();
|
|
15510
|
+
if (!frame.contentDocument) {
|
|
15511
|
+
throw "No document associated with iframe!";
|
|
15512
|
+
}
|
|
15513
|
+
const form = await getEARForm(frame.contentDocument, config, authority, request, logger, performanceClient);
|
|
15514
|
+
form.submit();
|
|
15515
|
+
return frame;
|
|
15516
|
+
}
|
|
15508
15517
|
/**
|
|
15509
15518
|
* Monitors an iframe content window until it loads a url with a known hash, or hits a specified timeout.
|
|
15510
15519
|
* @param iframe
|
|
@@ -15655,19 +15664,34 @@ class SilentIframeClient extends StandardInteractionClient {
|
|
|
15655
15664
|
}
|
|
15656
15665
|
// Create silent request
|
|
15657
15666
|
const silentRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, request.correlationId)(inputRequest, exports.InteractionType.Silent);
|
|
15667
|
+
silentRequest.platformBroker =
|
|
15668
|
+
NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, silentRequest.authenticationScheme);
|
|
15658
15669
|
preconnect(silentRequest.authority);
|
|
15659
|
-
|
|
15670
|
+
if (this.config.auth.protocolMode === ProtocolMode.EAR) {
|
|
15671
|
+
return this.executeEarFlow(silentRequest);
|
|
15672
|
+
}
|
|
15673
|
+
else {
|
|
15674
|
+
return this.executeCodeFlow(silentRequest);
|
|
15675
|
+
}
|
|
15676
|
+
}
|
|
15677
|
+
/**
|
|
15678
|
+
* Executes auth code + PKCE flow
|
|
15679
|
+
* @param request
|
|
15680
|
+
* @returns
|
|
15681
|
+
*/
|
|
15682
|
+
async executeCodeFlow(request) {
|
|
15660
15683
|
let authClient;
|
|
15684
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
15661
15685
|
try {
|
|
15662
15686
|
// Initialize the client
|
|
15663
15687
|
authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, request.correlationId)({
|
|
15664
15688
|
serverTelemetryManager,
|
|
15665
|
-
requestAuthority:
|
|
15666
|
-
requestAzureCloudOptions:
|
|
15667
|
-
requestExtraQueryParameters:
|
|
15668
|
-
account:
|
|
15689
|
+
requestAuthority: request.authority,
|
|
15690
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
15691
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
15692
|
+
account: request.account,
|
|
15669
15693
|
});
|
|
15670
|
-
return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, request.correlationId)(authClient,
|
|
15694
|
+
return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, request.correlationId)(authClient, request);
|
|
15671
15695
|
}
|
|
15672
15696
|
catch (e) {
|
|
15673
15697
|
if (e instanceof AuthError) {
|
|
@@ -15682,10 +15706,33 @@ class SilentIframeClient extends StandardInteractionClient {
|
|
|
15682
15706
|
this.performanceClient.addFields({
|
|
15683
15707
|
retryError: e.errorCode,
|
|
15684
15708
|
}, this.correlationId);
|
|
15685
|
-
|
|
15686
|
-
return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, this.correlationId)(authClient, retrySilentRequest);
|
|
15709
|
+
return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, this.correlationId)(authClient, request);
|
|
15687
15710
|
}
|
|
15688
15711
|
}
|
|
15712
|
+
/**
|
|
15713
|
+
* Executes EAR flow
|
|
15714
|
+
* @param request
|
|
15715
|
+
*/
|
|
15716
|
+
async executeEarFlow(request) {
|
|
15717
|
+
const correlationId = request.correlationId;
|
|
15718
|
+
const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, correlationId)({
|
|
15719
|
+
requestAuthority: request.authority,
|
|
15720
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
15721
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
15722
|
+
account: request.account,
|
|
15723
|
+
});
|
|
15724
|
+
const earJwk = await invokeAsync(generateEarKey, PerformanceEvents.GenerateEarKey, this.logger, this.performanceClient, correlationId)();
|
|
15725
|
+
const silentRequest = {
|
|
15726
|
+
...request,
|
|
15727
|
+
earJwk: earJwk,
|
|
15728
|
+
};
|
|
15729
|
+
const msalFrame = await invokeAsync(initiateEarRequest, PerformanceEvents.SilentHandlerInitiateAuthRequest, this.logger, this.performanceClient, correlationId)(this.config, discoveredAuthority, silentRequest, this.logger, this.performanceClient);
|
|
15730
|
+
const responseType = this.config.auth.OIDCOptions.serverResponseType;
|
|
15731
|
+
// Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
|
|
15732
|
+
const responseString = await invokeAsync(monitorIframeForHash, PerformanceEvents.SilentHandlerMonitorIframeForHash, this.logger, this.performanceClient, correlationId)(msalFrame, this.config.system.iframeHashTimeout, this.config.system.pollIntervalMilliseconds, this.performanceClient, this.logger, correlationId, responseType);
|
|
15733
|
+
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, correlationId)(responseString, responseType, this.logger);
|
|
15734
|
+
return invokeAsync(handleResponseEAR, PerformanceEvents.HandleResponseEar, this.logger, this.performanceClient, correlationId)(silentRequest, serverParams, this.apiId, this.config, discoveredAuthority, this.browserStorage, this.nativeStorage, this.eventHandler, this.logger, this.performanceClient, this.nativeMessageHandler);
|
|
15735
|
+
}
|
|
15689
15736
|
/**
|
|
15690
15737
|
* Currently Unsupported
|
|
15691
15738
|
*/
|
|
@@ -15702,44 +15749,20 @@ class SilentIframeClient extends StandardInteractionClient {
|
|
|
15702
15749
|
async silentTokenHelper(authClient, request) {
|
|
15703
15750
|
const correlationId = request.correlationId;
|
|
15704
15751
|
this.performanceClient.addQueueMeasurement(PerformanceEvents.SilentIframeClientTokenHelper, correlationId);
|
|
15705
|
-
const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient,
|
|
15752
|
+
const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, correlationId)(this.performanceClient, this.logger, correlationId);
|
|
15706
15753
|
const silentRequest = {
|
|
15707
15754
|
...request,
|
|
15708
15755
|
codeChallenge: pkceCodes.challenge,
|
|
15709
15756
|
};
|
|
15710
15757
|
// Create authorize request url
|
|
15711
|
-
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, correlationId)(this.config, authClient.authority,
|
|
15712
|
-
...silentRequest,
|
|
15713
|
-
platformBroker: NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, silentRequest.authenticationScheme),
|
|
15714
|
-
}, this.logger, this.performanceClient);
|
|
15758
|
+
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, correlationId)(this.config, authClient.authority, silentRequest, this.logger, this.performanceClient);
|
|
15715
15759
|
// Get the frame handle for the silent request
|
|
15716
|
-
const msalFrame = await invokeAsync(
|
|
15760
|
+
const msalFrame = await invokeAsync(initiateCodeRequest, PerformanceEvents.SilentHandlerInitiateAuthRequest, this.logger, this.performanceClient, correlationId)(navigateUrl, this.performanceClient, this.logger, correlationId, this.config.system.navigateFrameWait);
|
|
15717
15761
|
const responseType = this.config.auth.OIDCOptions.serverResponseType;
|
|
15718
15762
|
// Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
|
|
15719
15763
|
const responseString = await invokeAsync(monitorIframeForHash, PerformanceEvents.SilentHandlerMonitorIframeForHash, this.logger, this.performanceClient, correlationId)(msalFrame, this.config.system.iframeHashTimeout, this.config.system.pollIntervalMilliseconds, this.performanceClient, this.logger, correlationId, responseType);
|
|
15720
|
-
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient,
|
|
15721
|
-
|
|
15722
|
-
this.logger.verbose("Account id found in hash, calling WAM for token");
|
|
15723
|
-
if (!this.nativeMessageHandler) {
|
|
15724
|
-
throw createBrowserAuthError(nativeConnectionNotEstablished);
|
|
15725
|
-
}
|
|
15726
|
-
const nativeInteractionClient = new NativeInteractionClient(this.config, this.browserStorage, this.browserCrypto, this.logger, this.eventHandler, this.navigationClient, this.apiId, this.performanceClient, this.nativeMessageHandler, serverParams.accountId, this.browserStorage, correlationId);
|
|
15727
|
-
const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, silentRequest.state);
|
|
15728
|
-
return invokeAsync(nativeInteractionClient.acquireToken.bind(nativeInteractionClient), PerformanceEvents.NativeInteractionClientAcquireToken, this.logger, this.performanceClient, correlationId)({
|
|
15729
|
-
...silentRequest,
|
|
15730
|
-
state: userRequestState,
|
|
15731
|
-
prompt: silentRequest.prompt || PromptValue.NONE,
|
|
15732
|
-
});
|
|
15733
|
-
}
|
|
15734
|
-
const authCodeRequest = {
|
|
15735
|
-
...silentRequest,
|
|
15736
|
-
code: serverParams.code || "",
|
|
15737
|
-
codeVerifier: pkceCodes.verifier,
|
|
15738
|
-
};
|
|
15739
|
-
// Create silent handler
|
|
15740
|
-
const interactionHandler = new InteractionHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.performanceClient);
|
|
15741
|
-
// Handle response from hash string
|
|
15742
|
-
return invokeAsync(interactionHandler.handleCodeResponse.bind(interactionHandler), PerformanceEvents.HandleCodeResponse, this.logger, this.performanceClient, correlationId)(serverParams, silentRequest);
|
|
15764
|
+
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, correlationId)(responseString, responseType, this.logger);
|
|
15765
|
+
return invokeAsync(handleResponseCode, PerformanceEvents.HandleResponseCode, this.logger, this.performanceClient, correlationId)(request, serverParams, pkceCodes.verifier, this.apiId, this.config, authClient, this.browserStorage, this.nativeStorage, this.eventHandler, this.logger, this.performanceClient, this.nativeMessageHandler);
|
|
15743
15766
|
}
|
|
15744
15767
|
}
|
|
15745
15768
|
|
|
@@ -16268,31 +16291,38 @@ class StandardController {
|
|
|
16268
16291
|
* @returns
|
|
16269
16292
|
*/
|
|
16270
16293
|
async handleRedirectPromiseInternal(hash) {
|
|
16294
|
+
if (!this.browserStorage.isInteractionInProgress(true)) {
|
|
16295
|
+
this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
|
|
16296
|
+
return null;
|
|
16297
|
+
}
|
|
16271
16298
|
const loggedInAccounts = this.getAllAccounts();
|
|
16272
|
-
const
|
|
16273
|
-
const useNative =
|
|
16299
|
+
const platformBrokerRequest = this.browserStorage.getCachedNativeRequest();
|
|
16300
|
+
const useNative = platformBrokerRequest &&
|
|
16274
16301
|
NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeExtensionProvider) &&
|
|
16275
16302
|
this.nativeExtensionProvider &&
|
|
16276
16303
|
!hash;
|
|
16277
|
-
|
|
16278
|
-
? request?.correlationId
|
|
16279
|
-
: this.browserStorage.getTemporaryCache(TemporaryCacheKeys.CORRELATION_ID, true) || "";
|
|
16280
|
-
const rootMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenRedirect, correlationId);
|
|
16304
|
+
let rootMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenRedirect, platformBrokerRequest?.correlationId || "");
|
|
16281
16305
|
this.eventHandler.emitEvent(EventType.HANDLE_REDIRECT_START, exports.InteractionType.Redirect);
|
|
16282
16306
|
let redirectResponse;
|
|
16283
16307
|
if (useNative && this.nativeExtensionProvider) {
|
|
16284
16308
|
this.logger.trace("handleRedirectPromise - acquiring token from native platform");
|
|
16285
|
-
const nativeClient = new NativeInteractionClient(this.config, this.browserStorage, this.browserCrypto, this.logger, this.eventHandler, this.navigationClient, ApiId.handleRedirectPromise, this.performanceClient, this.nativeExtensionProvider,
|
|
16309
|
+
const nativeClient = new NativeInteractionClient(this.config, this.browserStorage, this.browserCrypto, this.logger, this.eventHandler, this.navigationClient, ApiId.handleRedirectPromise, this.performanceClient, this.nativeExtensionProvider, platformBrokerRequest.accountId, this.nativeInternalStorage, platformBrokerRequest.correlationId);
|
|
16286
16310
|
redirectResponse = invokeAsync(nativeClient.handleRedirectPromise.bind(nativeClient), PerformanceEvents.HandleNativeRedirectPromiseMeasurement, this.logger, this.performanceClient, rootMeasurement.event.correlationId)(this.performanceClient, rootMeasurement.event.correlationId);
|
|
16287
16311
|
}
|
|
16288
16312
|
else {
|
|
16313
|
+
const [standardRequest, codeVerifier] = this.browserStorage.getCachedRequest();
|
|
16314
|
+
const correlationId = standardRequest.correlationId;
|
|
16315
|
+
// Reset rootMeasurement now that we have correlationId
|
|
16316
|
+
rootMeasurement.discard();
|
|
16317
|
+
rootMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenRedirect, correlationId);
|
|
16289
16318
|
this.logger.trace("handleRedirectPromise - acquiring token from web flow");
|
|
16290
16319
|
const redirectClient = this.createRedirectClient(correlationId);
|
|
16291
|
-
redirectResponse = invokeAsync(redirectClient.handleRedirectPromise.bind(redirectClient), PerformanceEvents.HandleRedirectPromiseMeasurement, this.logger, this.performanceClient, rootMeasurement.event.correlationId)(hash, rootMeasurement);
|
|
16320
|
+
redirectResponse = invokeAsync(redirectClient.handleRedirectPromise.bind(redirectClient), PerformanceEvents.HandleRedirectPromiseMeasurement, this.logger, this.performanceClient, rootMeasurement.event.correlationId)(hash, standardRequest, codeVerifier, rootMeasurement);
|
|
16292
16321
|
}
|
|
16293
16322
|
return redirectResponse
|
|
16294
16323
|
.then((result) => {
|
|
16295
16324
|
if (result) {
|
|
16325
|
+
this.browserStorage.resetRequestCache();
|
|
16296
16326
|
// Emit login event if number of accounts change
|
|
16297
16327
|
const isLoggingIn = loggedInAccounts.length < this.getAllAccounts().length;
|
|
16298
16328
|
if (isLoggingIn) {
|
|
@@ -16324,6 +16354,7 @@ class StandardController {
|
|
|
16324
16354
|
return result;
|
|
16325
16355
|
})
|
|
16326
16356
|
.catch((e) => {
|
|
16357
|
+
this.browserStorage.resetRequestCache();
|
|
16327
16358
|
const eventError = e;
|
|
16328
16359
|
// Emit login event if there is an account
|
|
16329
16360
|
if (loggedInAccounts.length > 0) {
|
|
@@ -16417,7 +16448,6 @@ class StandardController {
|
|
|
16417
16448
|
const redirectClient = this.createRedirectClient(correlationId);
|
|
16418
16449
|
return redirectClient.acquireToken(request);
|
|
16419
16450
|
}
|
|
16420
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
16421
16451
|
throw e;
|
|
16422
16452
|
});
|
|
16423
16453
|
}
|
|
@@ -16428,6 +16458,7 @@ class StandardController {
|
|
|
16428
16458
|
return await result;
|
|
16429
16459
|
}
|
|
16430
16460
|
catch (e) {
|
|
16461
|
+
this.browserStorage.resetRequestCache();
|
|
16431
16462
|
atrMeasurement.end({ success: false }, e);
|
|
16432
16463
|
if (isLoggedIn) {
|
|
16433
16464
|
this.eventHandler.emitEvent(EventType.ACQUIRE_TOKEN_FAILURE, exports.InteractionType.Redirect, null, e);
|
|
@@ -16479,7 +16510,6 @@ class StandardController {
|
|
|
16479
16510
|
correlationId,
|
|
16480
16511
|
}, ApiId.acquireTokenPopup)
|
|
16481
16512
|
.then((response) => {
|
|
16482
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
16483
16513
|
atPopupMeasurement.end({
|
|
16484
16514
|
success: true,
|
|
16485
16515
|
isNativeBroker: true,
|
|
@@ -16499,7 +16529,6 @@ class StandardController {
|
|
|
16499
16529
|
const popupClient = this.createPopupClient(correlationId);
|
|
16500
16530
|
return popupClient.acquireToken(request, pkce);
|
|
16501
16531
|
}
|
|
16502
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
16503
16532
|
throw e;
|
|
16504
16533
|
});
|
|
16505
16534
|
}
|
|
@@ -16540,8 +16569,12 @@ class StandardController {
|
|
|
16540
16569
|
// Since this function is syncronous we need to reject
|
|
16541
16570
|
return Promise.reject(e);
|
|
16542
16571
|
})
|
|
16543
|
-
.finally(() =>
|
|
16544
|
-
this.
|
|
16572
|
+
.finally(async () => {
|
|
16573
|
+
this.browserStorage.setInteractionInProgress(false);
|
|
16574
|
+
if (this.config.system.asyncPopups) {
|
|
16575
|
+
await this.preGeneratePkceCodes(correlationId);
|
|
16576
|
+
}
|
|
16577
|
+
});
|
|
16545
16578
|
}
|
|
16546
16579
|
trackPageVisibilityWithMeasurement() {
|
|
16547
16580
|
const measurement = this.ssoSilentMeasurement ||
|
|
@@ -16844,7 +16877,9 @@ class StandardController {
|
|
|
16844
16877
|
preflightCheck$1(this.initialized);
|
|
16845
16878
|
this.browserStorage.setInteractionInProgress(true);
|
|
16846
16879
|
const popupClient = this.createPopupClient(correlationId);
|
|
16847
|
-
return popupClient.logout(logoutRequest)
|
|
16880
|
+
return popupClient.logout(logoutRequest).finally(() => {
|
|
16881
|
+
this.browserStorage.setInteractionInProgress(false);
|
|
16882
|
+
});
|
|
16848
16883
|
}
|
|
16849
16884
|
catch (e) {
|
|
16850
16885
|
// Since this function is syncronous we need to reject
|
|
@@ -17260,9 +17295,7 @@ class StandardController {
|
|
|
17260
17295
|
async acquireTokenSilentDeduped(request, account, correlationId) {
|
|
17261
17296
|
const thumbprint = getRequestThumbprint(this.config.auth.clientId, {
|
|
17262
17297
|
...request,
|
|
17263
|
-
authority: request.authority || this.config.auth.authority,
|
|
17264
|
-
correlationId: correlationId,
|
|
17265
|
-
}, account.homeAccountId);
|
|
17298
|
+
authority: request.authority || this.config.auth.authority}, account.homeAccountId);
|
|
17266
17299
|
const silentRequestKey = JSON.stringify(thumbprint);
|
|
17267
17300
|
const inProgressRequest = this.activeSilentTokenRequests.get(silentRequestKey);
|
|
17268
17301
|
if (typeof inProgressRequest === "undefined") {
|