@azure/msal-browser 4.8.0 → 4.9.0
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 +1 -1
- 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.d.ts.map +1 -1
- package/dist/config/Configuration.mjs +12 -3
- 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 +1 -1
- 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 +13 -3
- 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 +1 -1
- 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 -11
- 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 +1595 -1514
- package/lib/msal-browser.cjs.map +1 -1
- package/lib/msal-browser.js +1595 -1514
- 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/config/Configuration.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 +14 -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.0 2025-03-25 */
|
|
2
2
|
'use strict';
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
|
-
/*! @azure/msal-common v15.
|
|
5
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
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,8 +58,6 @@ 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
|
};
|
|
@@ -146,8 +141,17 @@ const CodeChallengeMethodValues = {
|
|
|
146
141
|
PLAIN: "plain",
|
|
147
142
|
S256: "S256",
|
|
148
143
|
};
|
|
144
|
+
/**
|
|
145
|
+
* Allowed values for response_type
|
|
146
|
+
*/
|
|
147
|
+
const OAuthResponseType = {
|
|
148
|
+
CODE: "code",
|
|
149
|
+
IDTOKEN_TOKEN: "id_token token",
|
|
150
|
+
IDTOKEN_TOKEN_REFRESHTOKEN: "id_token token refresh_token",
|
|
151
|
+
};
|
|
149
152
|
/**
|
|
150
153
|
* allowed values for server response type
|
|
154
|
+
* @deprecated Use ResponseMode instead
|
|
151
155
|
*/
|
|
152
156
|
const ServerResponseType = {
|
|
153
157
|
QUERY: "query",
|
|
@@ -157,7 +161,8 @@ const ServerResponseType = {
|
|
|
157
161
|
* allowed values for response_mode
|
|
158
162
|
*/
|
|
159
163
|
const ResponseMode = {
|
|
160
|
-
|
|
164
|
+
QUERY: "query",
|
|
165
|
+
FRAGMENT: "fragment",
|
|
161
166
|
FORM_POST: "form_post",
|
|
162
167
|
};
|
|
163
168
|
/**
|
|
@@ -299,7 +304,7 @@ const JsonWebTokenTypes = {
|
|
|
299
304
|
// Token renewal offset default in seconds
|
|
300
305
|
const DEFAULT_TOKEN_RENEWAL_OFFSET_SEC = 300;
|
|
301
306
|
|
|
302
|
-
/*! @azure/msal-common v15.
|
|
307
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
303
308
|
/*
|
|
304
309
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
305
310
|
* Licensed under the MIT License.
|
|
@@ -316,7 +321,7 @@ var AuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
|
316
321
|
unexpectedError: unexpectedError
|
|
317
322
|
});
|
|
318
323
|
|
|
319
|
-
/*! @azure/msal-common v15.
|
|
324
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
320
325
|
|
|
321
326
|
/*
|
|
322
327
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -365,7 +370,7 @@ function createAuthError(code, additionalMessage) {
|
|
|
365
370
|
: AuthErrorMessages[code]);
|
|
366
371
|
}
|
|
367
372
|
|
|
368
|
-
/*! @azure/msal-common v15.
|
|
373
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
369
374
|
/*
|
|
370
375
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
371
376
|
* Licensed under the MIT License.
|
|
@@ -463,7 +468,7 @@ var ClientAuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
|
463
468
|
userTimeoutReached: userTimeoutReached
|
|
464
469
|
});
|
|
465
470
|
|
|
466
|
-
/*! @azure/msal-common v15.
|
|
471
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
467
472
|
|
|
468
473
|
/*
|
|
469
474
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -715,7 +720,7 @@ function createClientAuthError(errorCode, additionalMessage) {
|
|
|
715
720
|
return new ClientAuthError(errorCode, additionalMessage);
|
|
716
721
|
}
|
|
717
722
|
|
|
718
|
-
/*! @azure/msal-common v15.
|
|
723
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
719
724
|
|
|
720
725
|
/*
|
|
721
726
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -754,7 +759,7 @@ const DEFAULT_CRYPTO_IMPLEMENTATION = {
|
|
|
754
759
|
},
|
|
755
760
|
};
|
|
756
761
|
|
|
757
|
-
/*! @azure/msal-common v15.
|
|
762
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
758
763
|
|
|
759
764
|
/*
|
|
760
765
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -945,12 +950,12 @@ class Logger {
|
|
|
945
950
|
}
|
|
946
951
|
}
|
|
947
952
|
|
|
948
|
-
/*! @azure/msal-common v15.
|
|
953
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
949
954
|
/* eslint-disable header/header */
|
|
950
955
|
const name$1 = "@azure/msal-common";
|
|
951
|
-
const version$1 = "15.
|
|
956
|
+
const version$1 = "15.4.0";
|
|
952
957
|
|
|
953
|
-
/*! @azure/msal-common v15.
|
|
958
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
954
959
|
/*
|
|
955
960
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
956
961
|
* Licensed under the MIT License.
|
|
@@ -970,7 +975,7 @@ const AzureCloudInstance = {
|
|
|
970
975
|
AzureUsGovernment: "https://login.microsoftonline.us",
|
|
971
976
|
};
|
|
972
977
|
|
|
973
|
-
/*! @azure/msal-common v15.
|
|
978
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
974
979
|
|
|
975
980
|
/*
|
|
976
981
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1031,7 +1036,7 @@ function checkMaxAge(authTime, maxAge) {
|
|
|
1031
1036
|
}
|
|
1032
1037
|
}
|
|
1033
1038
|
|
|
1034
|
-
/*! @azure/msal-common v15.
|
|
1039
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1035
1040
|
/*
|
|
1036
1041
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
1037
1042
|
* Licensed under the MIT License.
|
|
@@ -1086,7 +1091,7 @@ function wasClockTurnedBack(cachedAt) {
|
|
|
1086
1091
|
return cachedAtSec > nowSeconds();
|
|
1087
1092
|
}
|
|
1088
1093
|
|
|
1089
|
-
/*! @azure/msal-common v15.
|
|
1094
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1090
1095
|
|
|
1091
1096
|
/*
|
|
1092
1097
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1413,7 +1418,7 @@ function isAuthorityMetadataExpired(metadata) {
|
|
|
1413
1418
|
return metadata.expiresAt <= nowSeconds();
|
|
1414
1419
|
}
|
|
1415
1420
|
|
|
1416
|
-
/*! @azure/msal-common v15.
|
|
1421
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1417
1422
|
/*
|
|
1418
1423
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
1419
1424
|
* Licensed under the MIT License.
|
|
@@ -1467,7 +1472,7 @@ var ClientConfigurationErrorCodes = /*#__PURE__*/Object.freeze({
|
|
|
1467
1472
|
urlParseError: urlParseError
|
|
1468
1473
|
});
|
|
1469
1474
|
|
|
1470
|
-
/*! @azure/msal-common v15.
|
|
1475
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1471
1476
|
|
|
1472
1477
|
/*
|
|
1473
1478
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1605,7 +1610,7 @@ function createClientConfigurationError(errorCode) {
|
|
|
1605
1610
|
return new ClientConfigurationError(errorCode);
|
|
1606
1611
|
}
|
|
1607
1612
|
|
|
1608
|
-
/*! @azure/msal-common v15.
|
|
1613
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1609
1614
|
/*
|
|
1610
1615
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
1611
1616
|
* Licensed under the MIT License.
|
|
@@ -1702,7 +1707,7 @@ class StringUtils {
|
|
|
1702
1707
|
}
|
|
1703
1708
|
}
|
|
1704
1709
|
|
|
1705
|
-
/*! @azure/msal-common v15.
|
|
1710
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1706
1711
|
|
|
1707
1712
|
/*
|
|
1708
1713
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1893,7 +1898,7 @@ class ScopeSet {
|
|
|
1893
1898
|
}
|
|
1894
1899
|
}
|
|
1895
1900
|
|
|
1896
|
-
/*! @azure/msal-common v15.
|
|
1901
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1897
1902
|
|
|
1898
1903
|
/*
|
|
1899
1904
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1933,7 +1938,7 @@ function buildClientInfoFromHomeAccountId(homeAccountId) {
|
|
|
1933
1938
|
};
|
|
1934
1939
|
}
|
|
1935
1940
|
|
|
1936
|
-
/*! @azure/msal-common v15.
|
|
1941
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1937
1942
|
/*
|
|
1938
1943
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
1939
1944
|
* Licensed under the MIT License.
|
|
@@ -2012,7 +2017,7 @@ function updateAccountTenantProfileData(baseAccountInfo, tenantProfile, idTokenC
|
|
|
2012
2017
|
return updatedAccountInfo;
|
|
2013
2018
|
}
|
|
2014
2019
|
|
|
2015
|
-
/*! @azure/msal-common v15.
|
|
2020
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2016
2021
|
/*
|
|
2017
2022
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2018
2023
|
* Licensed under the MIT License.
|
|
@@ -2027,7 +2032,7 @@ const AuthorityType = {
|
|
|
2027
2032
|
Ciam: 3,
|
|
2028
2033
|
};
|
|
2029
2034
|
|
|
2030
|
-
/*! @azure/msal-common v15.
|
|
2035
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2031
2036
|
/*
|
|
2032
2037
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2033
2038
|
* Licensed under the MIT License.
|
|
@@ -2049,7 +2054,7 @@ function getTenantIdFromIdTokenClaims(idTokenClaims) {
|
|
|
2049
2054
|
return null;
|
|
2050
2055
|
}
|
|
2051
2056
|
|
|
2052
|
-
/*! @azure/msal-common v15.
|
|
2057
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2053
2058
|
/*
|
|
2054
2059
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2055
2060
|
* Licensed under the MIT License.
|
|
@@ -2058,11 +2063,22 @@ function getTenantIdFromIdTokenClaims(idTokenClaims) {
|
|
|
2058
2063
|
* Protocol modes supported by MSAL.
|
|
2059
2064
|
*/
|
|
2060
2065
|
const ProtocolMode = {
|
|
2066
|
+
/**
|
|
2067
|
+
* Auth Code + PKCE with Entra ID (formerly AAD) specific optimizations and features
|
|
2068
|
+
*/
|
|
2061
2069
|
AAD: "AAD",
|
|
2070
|
+
/**
|
|
2071
|
+
* Auth Code + PKCE without Entra ID specific optimizations and features. For use only with non-Microsoft owned authorities.
|
|
2072
|
+
* Support is limited for this mode.
|
|
2073
|
+
*/
|
|
2062
2074
|
OIDC: "OIDC",
|
|
2075
|
+
/**
|
|
2076
|
+
* Encrypted Authorize Response (EAR) with Entra ID specific optimizations and features
|
|
2077
|
+
*/
|
|
2078
|
+
EAR: "EAR",
|
|
2063
2079
|
};
|
|
2064
2080
|
|
|
2065
|
-
/*! @azure/msal-common v15.
|
|
2081
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2066
2082
|
|
|
2067
2083
|
/*
|
|
2068
2084
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2158,11 +2174,11 @@ class AccountEntity {
|
|
|
2158
2174
|
if (authority.authorityType === AuthorityType.Adfs) {
|
|
2159
2175
|
account.authorityType = CacheAccountType.ADFS_ACCOUNT_TYPE;
|
|
2160
2176
|
}
|
|
2161
|
-
else if (authority.protocolMode === ProtocolMode.
|
|
2162
|
-
account.authorityType = CacheAccountType.
|
|
2177
|
+
else if (authority.protocolMode === ProtocolMode.OIDC) {
|
|
2178
|
+
account.authorityType = CacheAccountType.GENERIC_ACCOUNT_TYPE;
|
|
2163
2179
|
}
|
|
2164
2180
|
else {
|
|
2165
|
-
account.authorityType = CacheAccountType.
|
|
2181
|
+
account.authorityType = CacheAccountType.MSSTS_ACCOUNT_TYPE;
|
|
2166
2182
|
}
|
|
2167
2183
|
let clientInfo;
|
|
2168
2184
|
if (accountDetails.clientInfo && base64Decode) {
|
|
@@ -2305,7 +2321,7 @@ class AccountEntity {
|
|
|
2305
2321
|
}
|
|
2306
2322
|
}
|
|
2307
2323
|
|
|
2308
|
-
/*! @azure/msal-common v15.
|
|
2324
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2309
2325
|
|
|
2310
2326
|
/*
|
|
2311
2327
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2340,6 +2356,7 @@ function getDeserializedResponse(responseString) {
|
|
|
2340
2356
|
const deserializedHash = Object.fromEntries(new URLSearchParams(normalizedResponse));
|
|
2341
2357
|
// Check for known response properties
|
|
2342
2358
|
if (deserializedHash.code ||
|
|
2359
|
+
deserializedHash.ear_jwe ||
|
|
2343
2360
|
deserializedHash.error ||
|
|
2344
2361
|
deserializedHash.error_description ||
|
|
2345
2362
|
deserializedHash.state) {
|
|
@@ -2362,7 +2379,7 @@ function mapToQueryString(parameters) {
|
|
|
2362
2379
|
return queryParameterArray.join("&");
|
|
2363
2380
|
}
|
|
2364
2381
|
|
|
2365
|
-
/*! @azure/msal-common v15.
|
|
2382
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2366
2383
|
|
|
2367
2384
|
/*
|
|
2368
2385
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2526,7 +2543,7 @@ class UrlString {
|
|
|
2526
2543
|
}
|
|
2527
2544
|
}
|
|
2528
2545
|
|
|
2529
|
-
/*! @azure/msal-common v15.
|
|
2546
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2530
2547
|
|
|
2531
2548
|
/*
|
|
2532
2549
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2666,7 +2683,7 @@ function getCloudDiscoveryMetadataFromNetworkResponse(response, authorityHost) {
|
|
|
2666
2683
|
return null;
|
|
2667
2684
|
}
|
|
2668
2685
|
|
|
2669
|
-
/*! @azure/msal-common v15.
|
|
2686
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2670
2687
|
/*
|
|
2671
2688
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2672
2689
|
* Licensed under the MIT License.
|
|
@@ -2674,7 +2691,7 @@ function getCloudDiscoveryMetadataFromNetworkResponse(response, authorityHost) {
|
|
|
2674
2691
|
const cacheQuotaExceededErrorCode = "cache_quota_exceeded";
|
|
2675
2692
|
const cacheUnknownErrorCode = "cache_error_unknown";
|
|
2676
2693
|
|
|
2677
|
-
/*! @azure/msal-common v15.
|
|
2694
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2678
2695
|
|
|
2679
2696
|
/*
|
|
2680
2697
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2701,7 +2718,7 @@ class CacheError extends Error {
|
|
|
2701
2718
|
}
|
|
2702
2719
|
}
|
|
2703
2720
|
|
|
2704
|
-
/*! @azure/msal-common v15.
|
|
2721
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2705
2722
|
|
|
2706
2723
|
/*
|
|
2707
2724
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -3886,7 +3903,7 @@ class DefaultStorageClass extends CacheManager {
|
|
|
3886
3903
|
}
|
|
3887
3904
|
}
|
|
3888
3905
|
|
|
3889
|
-
/*! @azure/msal-common v15.
|
|
3906
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
3890
3907
|
|
|
3891
3908
|
/*
|
|
3892
3909
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -3985,7 +4002,7 @@ function isOidcProtocolMode(config) {
|
|
|
3985
4002
|
return (config.authOptions.authority.options.protocolMode === ProtocolMode.OIDC);
|
|
3986
4003
|
}
|
|
3987
4004
|
|
|
3988
|
-
/*! @azure/msal-common v15.
|
|
4005
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
3989
4006
|
/*
|
|
3990
4007
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3991
4008
|
* Licensed under the MIT License.
|
|
@@ -3995,7 +4012,7 @@ const CcsCredentialType = {
|
|
|
3995
4012
|
UPN: "UPN",
|
|
3996
4013
|
};
|
|
3997
4014
|
|
|
3998
|
-
/*! @azure/msal-common v15.
|
|
4015
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
3999
4016
|
/*
|
|
4000
4017
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4001
4018
|
* Licensed under the MIT License.
|
|
@@ -4041,9 +4058,11 @@ const DOMAIN_HINT = "domain_hint";
|
|
|
4041
4058
|
const X_CLIENT_EXTRA_SKU = "x-client-xtra-sku";
|
|
4042
4059
|
const BROKER_CLIENT_ID = "brk_client_id";
|
|
4043
4060
|
const BROKER_REDIRECT_URI = "brk_redirect_uri";
|
|
4044
|
-
const INSTANCE_AWARE = "instance_aware";
|
|
4061
|
+
const INSTANCE_AWARE = "instance_aware";
|
|
4062
|
+
const EAR_JWK = "ear_jwk";
|
|
4063
|
+
const EAR_JWE_CRYPTO = "ear_jwe_crypto";
|
|
4045
4064
|
|
|
4046
|
-
/*! @azure/msal-common v15.
|
|
4065
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4047
4066
|
|
|
4048
4067
|
/*
|
|
4049
4068
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -4062,10 +4081,12 @@ function instrumentBrokerParams(parameters, correlationId, performanceClient) {
|
|
|
4062
4081
|
}
|
|
4063
4082
|
}
|
|
4064
4083
|
/**
|
|
4065
|
-
*
|
|
4084
|
+
* Add the given response_type
|
|
4085
|
+
* @param parameters
|
|
4086
|
+
* @param responseType
|
|
4066
4087
|
*/
|
|
4067
|
-
function
|
|
4068
|
-
parameters.set(RESPONSE_TYPE,
|
|
4088
|
+
function addResponseType(parameters, responseType) {
|
|
4089
|
+
parameters.set(RESPONSE_TYPE, responseType);
|
|
4069
4090
|
}
|
|
4070
4091
|
/**
|
|
4071
4092
|
* add response_mode. defaults to query.
|
|
@@ -4396,9 +4417,20 @@ function addBrokerParameters(parameters, brokerClientId, brokerRedirectUri) {
|
|
|
4396
4417
|
if (!parameters.has(BROKER_REDIRECT_URI)) {
|
|
4397
4418
|
parameters.set(BROKER_REDIRECT_URI, brokerRedirectUri);
|
|
4398
4419
|
}
|
|
4420
|
+
}
|
|
4421
|
+
/**
|
|
4422
|
+
* Add EAR (Encrypted Authorize Response) request parameters
|
|
4423
|
+
* @param parameters
|
|
4424
|
+
* @param jwk
|
|
4425
|
+
*/
|
|
4426
|
+
function addEARParameters(parameters, jwk) {
|
|
4427
|
+
parameters.set(EAR_JWK, encodeURIComponent(jwk));
|
|
4428
|
+
// ear_jwe_crypto will always have value: {"alg":"dir","enc":"A256GCM"} so we can hardcode this
|
|
4429
|
+
const jweCryptoB64Encoded = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0";
|
|
4430
|
+
parameters.set(EAR_JWE_CRYPTO, jweCryptoB64Encoded);
|
|
4399
4431
|
}
|
|
4400
4432
|
|
|
4401
|
-
/*! @azure/msal-common v15.
|
|
4433
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4402
4434
|
/*
|
|
4403
4435
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4404
4436
|
* Licensed under the MIT License.
|
|
@@ -4410,7 +4442,7 @@ function isOpenIdConfigResponse(response) {
|
|
|
4410
4442
|
response.hasOwnProperty("jwks_uri"));
|
|
4411
4443
|
}
|
|
4412
4444
|
|
|
4413
|
-
/*! @azure/msal-common v15.
|
|
4445
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4414
4446
|
/*
|
|
4415
4447
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4416
4448
|
* Licensed under the MIT License.
|
|
@@ -4420,7 +4452,7 @@ function isCloudInstanceDiscoveryResponse(response) {
|
|
|
4420
4452
|
response.hasOwnProperty("metadata"));
|
|
4421
4453
|
}
|
|
4422
4454
|
|
|
4423
|
-
/*! @azure/msal-common v15.
|
|
4455
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4424
4456
|
/*
|
|
4425
4457
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4426
4458
|
* Licensed under the MIT License.
|
|
@@ -4430,7 +4462,7 @@ function isCloudInstanceDiscoveryErrorResponse(response) {
|
|
|
4430
4462
|
response.hasOwnProperty("error_description"));
|
|
4431
4463
|
}
|
|
4432
4464
|
|
|
4433
|
-
/*! @azure/msal-common v15.
|
|
4465
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4434
4466
|
/*
|
|
4435
4467
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4436
4468
|
* Licensed under the MIT License.
|
|
@@ -4616,6 +4648,9 @@ const PerformanceEvents = {
|
|
|
4616
4648
|
*/
|
|
4617
4649
|
HandleCodeResponseFromServer: "handleCodeResponseFromServer",
|
|
4618
4650
|
HandleCodeResponse: "handleCodeResponse",
|
|
4651
|
+
HandleResponseEar: "handleResponseEar",
|
|
4652
|
+
HandleResponsePlatformBroker: "handleResponsePlatformBroker",
|
|
4653
|
+
HandleResponseCode: "handleResponseCode",
|
|
4619
4654
|
UpdateTokenEndpointAuthority: "updateTokenEndpointAuthority",
|
|
4620
4655
|
/**
|
|
4621
4656
|
* APIs in Authorization Code Client (msal-common)
|
|
@@ -4682,6 +4717,8 @@ const PerformanceEvents = {
|
|
|
4682
4717
|
UrlEncodeArr: "urlEncodeArr",
|
|
4683
4718
|
Encrypt: "encrypt",
|
|
4684
4719
|
Decrypt: "decrypt",
|
|
4720
|
+
GenerateEarKey: "generateEarKey",
|
|
4721
|
+
DecryptEarResponse: "decryptEarResponse",
|
|
4685
4722
|
};
|
|
4686
4723
|
const PerformanceEventAbbreviations = new Map([
|
|
4687
4724
|
[PerformanceEvents.AcquireTokenByCode, "ATByCode"],
|
|
@@ -4799,6 +4836,12 @@ const PerformanceEventAbbreviations = new Map([
|
|
|
4799
4836
|
"HandleCodeResFromServer",
|
|
4800
4837
|
],
|
|
4801
4838
|
[PerformanceEvents.HandleCodeResponse, "HandleCodeResp"],
|
|
4839
|
+
[PerformanceEvents.HandleResponseEar, "HandleRespEar"],
|
|
4840
|
+
[PerformanceEvents.HandleResponseCode, "HandleRespCode"],
|
|
4841
|
+
[
|
|
4842
|
+
PerformanceEvents.HandleResponsePlatformBroker,
|
|
4843
|
+
"HandleRespPlatBroker",
|
|
4844
|
+
],
|
|
4802
4845
|
[PerformanceEvents.UpdateTokenEndpointAuthority, "UpdTEndpointAuth"],
|
|
4803
4846
|
[PerformanceEvents.AuthClientAcquireToken, "AuthClientAT"],
|
|
4804
4847
|
[PerformanceEvents.AuthClientExecuteTokenRequest, "AuthClientExecTReq"],
|
|
@@ -4901,6 +4944,8 @@ const PerformanceEventAbbreviations = new Map([
|
|
|
4901
4944
|
[PerformanceEvents.UrlEncodeArr, "urlEncArr"],
|
|
4902
4945
|
[PerformanceEvents.Encrypt, "encrypt"],
|
|
4903
4946
|
[PerformanceEvents.Decrypt, "decrypt"],
|
|
4947
|
+
[PerformanceEvents.GenerateEarKey, "genEarKey"],
|
|
4948
|
+
[PerformanceEvents.DecryptEarResponse, "decryptEarResp"],
|
|
4904
4949
|
]);
|
|
4905
4950
|
/**
|
|
4906
4951
|
* State of the performance event.
|
|
@@ -4930,7 +4975,7 @@ const IntFields = new Set([
|
|
|
4930
4975
|
"encryptedCacheExpiredCount",
|
|
4931
4976
|
]);
|
|
4932
4977
|
|
|
4933
|
-
/*! @azure/msal-common v15.
|
|
4978
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4934
4979
|
/*
|
|
4935
4980
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4936
4981
|
* Licensed under the MIT License.
|
|
@@ -5026,7 +5071,7 @@ const invokeAsync = (callback, eventName, logger, telemetryClient, correlationId
|
|
|
5026
5071
|
};
|
|
5027
5072
|
};
|
|
5028
5073
|
|
|
5029
|
-
/*! @azure/msal-common v15.
|
|
5074
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
5030
5075
|
|
|
5031
5076
|
/*
|
|
5032
5077
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -5135,7 +5180,7 @@ RegionDiscovery.IMDS_OPTIONS = {
|
|
|
5135
5180
|
},
|
|
5136
5181
|
};
|
|
5137
5182
|
|
|
5138
|
-
/*! @azure/msal-common v15.
|
|
5183
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
5139
5184
|
|
|
5140
5185
|
/*
|
|
5141
5186
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -5313,7 +5358,7 @@ class Authority {
|
|
|
5313
5358
|
return (authorityUri.PathSegments.length === 1 &&
|
|
5314
5359
|
!Authority.reservedTenantDomains.has(authorityUri.PathSegments[0]) &&
|
|
5315
5360
|
this.getAuthorityType(authorityUri) === AuthorityType.Default &&
|
|
5316
|
-
this.protocolMode
|
|
5361
|
+
this.protocolMode !== ProtocolMode.OIDC);
|
|
5317
5362
|
}
|
|
5318
5363
|
/**
|
|
5319
5364
|
* Replaces tenant in url path with current tenant. Defaults to common.
|
|
@@ -5360,7 +5405,7 @@ class Authority {
|
|
|
5360
5405
|
const canonicalAuthorityHost = this.hostnameAndPort;
|
|
5361
5406
|
if (this.canonicalAuthority.endsWith("v2.0/") ||
|
|
5362
5407
|
this.authorityType === AuthorityType.Adfs ||
|
|
5363
|
-
(this.protocolMode
|
|
5408
|
+
(this.protocolMode === ProtocolMode.OIDC &&
|
|
5364
5409
|
!this.isAliasOfKnownMicrosoftAuthority(canonicalAuthorityHost))) {
|
|
5365
5410
|
return `${this.canonicalAuthority}.well-known/openid-configuration`;
|
|
5366
5411
|
}
|
|
@@ -5974,7 +6019,7 @@ function buildStaticAuthorityOptions(authOptions) {
|
|
|
5974
6019
|
};
|
|
5975
6020
|
}
|
|
5976
6021
|
|
|
5977
|
-
/*! @azure/msal-common v15.
|
|
6022
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
5978
6023
|
|
|
5979
6024
|
/*
|
|
5980
6025
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6005,7 +6050,7 @@ async function createDiscoveredInstance(authorityUri, networkClient, cacheManage
|
|
|
6005
6050
|
}
|
|
6006
6051
|
}
|
|
6007
6052
|
|
|
6008
|
-
/*! @azure/msal-common v15.
|
|
6053
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6009
6054
|
|
|
6010
6055
|
/*
|
|
6011
6056
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6024,7 +6069,7 @@ class ServerError extends AuthError {
|
|
|
6024
6069
|
}
|
|
6025
6070
|
}
|
|
6026
6071
|
|
|
6027
|
-
/*! @azure/msal-common v15.
|
|
6072
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6028
6073
|
/*
|
|
6029
6074
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
6030
6075
|
* Licensed under the MIT License.
|
|
@@ -6045,7 +6090,7 @@ function getRequestThumbprint(clientId, request, homeAccountId) {
|
|
|
6045
6090
|
};
|
|
6046
6091
|
}
|
|
6047
6092
|
|
|
6048
|
-
/*! @azure/msal-common v15.
|
|
6093
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6049
6094
|
|
|
6050
6095
|
/*
|
|
6051
6096
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6132,7 +6177,7 @@ class ThrottlingUtils {
|
|
|
6132
6177
|
}
|
|
6133
6178
|
}
|
|
6134
6179
|
|
|
6135
|
-
/*! @azure/msal-common v15.
|
|
6180
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6136
6181
|
|
|
6137
6182
|
/*
|
|
6138
6183
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6162,7 +6207,7 @@ function createNetworkError(error, httpStatus, responseHeaders) {
|
|
|
6162
6207
|
return new NetworkError(error, httpStatus, responseHeaders);
|
|
6163
6208
|
}
|
|
6164
6209
|
|
|
6165
|
-
/*! @azure/msal-common v15.
|
|
6210
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6166
6211
|
|
|
6167
6212
|
/*
|
|
6168
6213
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6310,7 +6355,7 @@ class BaseClient {
|
|
|
6310
6355
|
}
|
|
6311
6356
|
}
|
|
6312
6357
|
|
|
6313
|
-
/*! @azure/msal-common v15.
|
|
6358
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6314
6359
|
/*
|
|
6315
6360
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
6316
6361
|
* Licensed under the MIT License.
|
|
@@ -6336,7 +6381,7 @@ var InteractionRequiredAuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
|
6336
6381
|
refreshTokenExpired: refreshTokenExpired
|
|
6337
6382
|
});
|
|
6338
6383
|
|
|
6339
|
-
/*! @azure/msal-common v15.
|
|
6384
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6340
6385
|
|
|
6341
6386
|
/*
|
|
6342
6387
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6424,7 +6469,7 @@ function createInteractionRequiredAuthError(errorCode) {
|
|
|
6424
6469
|
return new InteractionRequiredAuthError(errorCode, InteractionRequiredAuthErrorMessages[errorCode]);
|
|
6425
6470
|
}
|
|
6426
6471
|
|
|
6427
|
-
/*! @azure/msal-common v15.
|
|
6472
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6428
6473
|
|
|
6429
6474
|
/*
|
|
6430
6475
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6496,7 +6541,7 @@ class ProtocolUtils {
|
|
|
6496
6541
|
}
|
|
6497
6542
|
}
|
|
6498
6543
|
|
|
6499
|
-
/*! @azure/msal-common v15.
|
|
6544
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6500
6545
|
|
|
6501
6546
|
/*
|
|
6502
6547
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6580,7 +6625,7 @@ class PopTokenGenerator {
|
|
|
6580
6625
|
}
|
|
6581
6626
|
}
|
|
6582
6627
|
|
|
6583
|
-
/*! @azure/msal-common v15.
|
|
6628
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6584
6629
|
/*
|
|
6585
6630
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
6586
6631
|
* Licensed under the MIT License.
|
|
@@ -6607,7 +6652,7 @@ class PopTokenGenerator {
|
|
|
6607
6652
|
}
|
|
6608
6653
|
}
|
|
6609
6654
|
|
|
6610
|
-
/*! @azure/msal-common v15.
|
|
6655
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6611
6656
|
|
|
6612
6657
|
/*
|
|
6613
6658
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6938,7 +6983,7 @@ function buildAccountToCache(cacheStorage, authority, homeAccountId, base64Decod
|
|
|
6938
6983
|
return baseAccount;
|
|
6939
6984
|
}
|
|
6940
6985
|
|
|
6941
|
-
/*! @azure/msal-common v15.
|
|
6986
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6942
6987
|
|
|
6943
6988
|
/*
|
|
6944
6989
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7005,7 +7050,7 @@ class RequestValidator {
|
|
|
7005
7050
|
}
|
|
7006
7051
|
}
|
|
7007
7052
|
|
|
7008
|
-
/*! @azure/msal-common v15.
|
|
7053
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7009
7054
|
/*
|
|
7010
7055
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
7011
7056
|
* Licensed under the MIT License.
|
|
@@ -7023,7 +7068,7 @@ async function getClientAssertion(clientAssertion, clientId, tokenEndpoint) {
|
|
|
7023
7068
|
}
|
|
7024
7069
|
}
|
|
7025
7070
|
|
|
7026
|
-
/*! @azure/msal-common v15.
|
|
7071
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7027
7072
|
|
|
7028
7073
|
/*
|
|
7029
7074
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7256,7 +7301,7 @@ class AuthorizationCodeClient extends BaseClient {
|
|
|
7256
7301
|
}
|
|
7257
7302
|
}
|
|
7258
7303
|
|
|
7259
|
-
/*! @azure/msal-common v15.
|
|
7304
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7260
7305
|
|
|
7261
7306
|
/*
|
|
7262
7307
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7465,7 +7510,7 @@ class RefreshTokenClient extends BaseClient {
|
|
|
7465
7510
|
}
|
|
7466
7511
|
}
|
|
7467
7512
|
|
|
7468
|
-
/*! @azure/msal-common v15.
|
|
7513
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7469
7514
|
|
|
7470
7515
|
/*
|
|
7471
7516
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7563,7 +7608,7 @@ class SilentFlowClient extends BaseClient {
|
|
|
7563
7608
|
}
|
|
7564
7609
|
}
|
|
7565
7610
|
|
|
7566
|
-
/*! @azure/msal-common v15.
|
|
7611
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7567
7612
|
|
|
7568
7613
|
/*
|
|
7569
7614
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7578,7 +7623,7 @@ const StubbedNetworkModule = {
|
|
|
7578
7623
|
},
|
|
7579
7624
|
};
|
|
7580
7625
|
|
|
7581
|
-
/*! @azure/msal-common v15.
|
|
7626
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7582
7627
|
|
|
7583
7628
|
/*
|
|
7584
7629
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7707,10 +7752,10 @@ function getStandardAuthorizeRequestParameters(authOptions, request, logger, per
|
|
|
7707
7752
|
if (request.embeddedClientId) {
|
|
7708
7753
|
addBrokerParameters(parameters, authOptions.clientId, authOptions.redirectUri);
|
|
7709
7754
|
}
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7755
|
+
// If extraQueryParameters includes instance_aware its value will be added when extraQueryParameters are added
|
|
7756
|
+
if (authOptions.instanceAware &&
|
|
7757
|
+
(!request.extraQueryParameters ||
|
|
7758
|
+
!Object.keys(request.extraQueryParameters).includes(INSTANCE_AWARE))) {
|
|
7714
7759
|
addInstanceAware(parameters);
|
|
7715
7760
|
}
|
|
7716
7761
|
return parameters;
|
|
@@ -7802,7 +7847,7 @@ function extractLoginHint(account) {
|
|
|
7802
7847
|
return account.idTokenClaims?.login_hint || null;
|
|
7803
7848
|
}
|
|
7804
7849
|
|
|
7805
|
-
/*! @azure/msal-common v15.
|
|
7850
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7806
7851
|
|
|
7807
7852
|
/*
|
|
7808
7853
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7860,7 +7905,7 @@ class AuthenticationHeaderParser {
|
|
|
7860
7905
|
}
|
|
7861
7906
|
}
|
|
7862
7907
|
|
|
7863
|
-
/*! @azure/msal-common v15.
|
|
7908
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7864
7909
|
|
|
7865
7910
|
/*
|
|
7866
7911
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8123,7 +8168,7 @@ class ServerTelemetryManager {
|
|
|
8123
8168
|
}
|
|
8124
8169
|
}
|
|
8125
8170
|
|
|
8126
|
-
/*! @azure/msal-common v15.
|
|
8171
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
8127
8172
|
/*
|
|
8128
8173
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
8129
8174
|
* Licensed under the MIT License.
|
|
@@ -8131,7 +8176,7 @@ class ServerTelemetryManager {
|
|
|
8131
8176
|
const missingKidError = "missing_kid_error";
|
|
8132
8177
|
const missingAlgError = "missing_alg_error";
|
|
8133
8178
|
|
|
8134
|
-
/*! @azure/msal-common v15.
|
|
8179
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
8135
8180
|
|
|
8136
8181
|
/*
|
|
8137
8182
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8156,7 +8201,7 @@ function createJoseHeaderError(code) {
|
|
|
8156
8201
|
return new JoseHeaderError(code, JoseHeaderErrorMessages[code]);
|
|
8157
8202
|
}
|
|
8158
8203
|
|
|
8159
|
-
/*! @azure/msal-common v15.
|
|
8204
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
8160
8205
|
|
|
8161
8206
|
/*
|
|
8162
8207
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8196,7 +8241,7 @@ class JoseHeader {
|
|
|
8196
8241
|
}
|
|
8197
8242
|
}
|
|
8198
8243
|
|
|
8199
|
-
/*! @azure/msal-common v15.
|
|
8244
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
8200
8245
|
|
|
8201
8246
|
/*
|
|
8202
8247
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8275,7 +8320,7 @@ class StubPerformanceClient {
|
|
|
8275
8320
|
}
|
|
8276
8321
|
}
|
|
8277
8322
|
|
|
8278
|
-
/*! @azure/msal-common v15.
|
|
8323
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
8279
8324
|
|
|
8280
8325
|
/*
|
|
8281
8326
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8889,6 +8934,8 @@ class PerformanceClient {
|
|
|
8889
8934
|
* Licensed under the MIT License.
|
|
8890
8935
|
*/
|
|
8891
8936
|
const pkceNotCreated = "pkce_not_created";
|
|
8937
|
+
const earJwkEmpty = "ear_jwk_empty";
|
|
8938
|
+
const earJweEmpty = "ear_jwe_empty";
|
|
8892
8939
|
const cryptoNonExistent = "crypto_nonexistent";
|
|
8893
8940
|
const emptyNavigateUri = "empty_navigate_uri";
|
|
8894
8941
|
const hashEmptyError = "hash_empty_error";
|
|
@@ -8911,7 +8958,6 @@ const noAccountError = "no_account_error";
|
|
|
8911
8958
|
const silentPromptValueError = "silent_prompt_value_error";
|
|
8912
8959
|
const noTokenRequestCacheError = "no_token_request_cache_error";
|
|
8913
8960
|
const unableToParseTokenRequestCacheError = "unable_to_parse_token_request_cache_error";
|
|
8914
|
-
const noCachedAuthorityError = "no_cached_authority_error";
|
|
8915
8961
|
const authRequestNotSetError = "auth_request_not_set_error";
|
|
8916
8962
|
const invalidCacheType = "invalid_cache_type";
|
|
8917
8963
|
const nonBrowserEnvironment = "non_browser_environment";
|
|
@@ -8935,7 +8981,8 @@ const nativePromptNotSupported = "native_prompt_not_supported";
|
|
|
8935
8981
|
const invalidBase64String = "invalid_base64_string";
|
|
8936
8982
|
const invalidPopTokenRequest = "invalid_pop_token_request";
|
|
8937
8983
|
const failedToBuildHeaders = "failed_to_build_headers";
|
|
8938
|
-
const failedToParseHeaders = "failed_to_parse_headers";
|
|
8984
|
+
const failedToParseHeaders = "failed_to_parse_headers";
|
|
8985
|
+
const failedToDecryptEarResponse = "failed_to_decrypt_ear_response";
|
|
8939
8986
|
|
|
8940
8987
|
var BrowserAuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
8941
8988
|
__proto__: null,
|
|
@@ -8948,9 +8995,12 @@ var BrowserAuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
|
8948
8995
|
cryptoNonExistent: cryptoNonExistent,
|
|
8949
8996
|
databaseNotOpen: databaseNotOpen,
|
|
8950
8997
|
databaseUnavailable: databaseUnavailable,
|
|
8998
|
+
earJweEmpty: earJweEmpty,
|
|
8999
|
+
earJwkEmpty: earJwkEmpty,
|
|
8951
9000
|
emptyNavigateUri: emptyNavigateUri,
|
|
8952
9001
|
emptyWindowError: emptyWindowError,
|
|
8953
9002
|
failedToBuildHeaders: failedToBuildHeaders,
|
|
9003
|
+
failedToDecryptEarResponse: failedToDecryptEarResponse,
|
|
8954
9004
|
failedToParseHeaders: failedToParseHeaders,
|
|
8955
9005
|
failedToParseResponse: failedToParseResponse,
|
|
8956
9006
|
getRequestFailed: getRequestFailed,
|
|
@@ -8968,7 +9018,6 @@ var BrowserAuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
|
8968
9018
|
nativeHandshakeTimeout: nativeHandshakeTimeout,
|
|
8969
9019
|
nativePromptNotSupported: nativePromptNotSupported,
|
|
8970
9020
|
noAccountError: noAccountError,
|
|
8971
|
-
noCachedAuthorityError: noCachedAuthorityError,
|
|
8972
9021
|
noNetworkConnectivity: noNetworkConnectivity,
|
|
8973
9022
|
noStateInHash: noStateInHash,
|
|
8974
9023
|
noTokenRequestCacheError: noTokenRequestCacheError,
|
|
@@ -8999,6 +9048,8 @@ const ErrorLink = "For more visit: aka.ms/msaljs/browser-errors";
|
|
|
8999
9048
|
*/
|
|
9000
9049
|
const BrowserAuthErrorMessages = {
|
|
9001
9050
|
[pkceNotCreated]: "The PKCE code challenge and verifier could not be generated.",
|
|
9051
|
+
[earJwkEmpty]: "No EAR encryption key provided. This is unexpected.",
|
|
9052
|
+
[earJweEmpty]: "Server response does not contain ear_jwe property. This is unexpected.",
|
|
9002
9053
|
[cryptoNonExistent]: "The crypto object or function is not available.",
|
|
9003
9054
|
[emptyNavigateUri]: "Navigation URI is empty. Please check stack trace for more info.",
|
|
9004
9055
|
[hashEmptyError]: `Hash value cannot be processed because it is empty. Please verify that your redirectUri is not clearing the hash. ${ErrorLink}`,
|
|
@@ -9021,7 +9072,6 @@ const BrowserAuthErrorMessages = {
|
|
|
9021
9072
|
[silentPromptValueError]: "The value given for the prompt value is not valid for silent requests - must be set to 'none' or 'no_session'.",
|
|
9022
9073
|
[noTokenRequestCacheError]: "No token request found in cache.",
|
|
9023
9074
|
[unableToParseTokenRequestCacheError]: "The cached token request could not be parsed.",
|
|
9024
|
-
[noCachedAuthorityError]: "No cached authority found.",
|
|
9025
9075
|
[authRequestNotSetError]: "Auth Request not set. Please ensure initiateAuthRequest was called from the InteractionHandler",
|
|
9026
9076
|
[invalidCacheType]: "Invalid cache type",
|
|
9027
9077
|
[nonBrowserEnvironment]: "Login and token requests are not supported in non-browser environments.",
|
|
@@ -9046,6 +9096,7 @@ const BrowserAuthErrorMessages = {
|
|
|
9046
9096
|
[invalidPopTokenRequest]: "Invalid PoP token request. The request should not have both a popKid value and signPopToken set to true.",
|
|
9047
9097
|
[failedToBuildHeaders]: "Failed to build request headers object.",
|
|
9048
9098
|
[failedToParseHeaders]: "Failed to parse response headers",
|
|
9099
|
+
[failedToDecryptEarResponse]: "Failed to decrypt ear response",
|
|
9049
9100
|
};
|
|
9050
9101
|
/**
|
|
9051
9102
|
* BrowserAuthErrorMessage class containing string constants used by error codes and messages.
|
|
@@ -9148,10 +9199,6 @@ const BrowserAuthErrorMessage = {
|
|
|
9148
9199
|
code: unableToParseTokenRequestCacheError,
|
|
9149
9200
|
desc: BrowserAuthErrorMessages[unableToParseTokenRequestCacheError],
|
|
9150
9201
|
},
|
|
9151
|
-
noCachedAuthorityError: {
|
|
9152
|
-
code: noCachedAuthorityError,
|
|
9153
|
-
desc: BrowserAuthErrorMessages[noCachedAuthorityError],
|
|
9154
|
-
},
|
|
9155
9202
|
authRequestNotSet: {
|
|
9156
9203
|
code: authRequestNotSetError,
|
|
9157
9204
|
desc: BrowserAuthErrorMessages[authRequestNotSetError],
|
|
@@ -9319,21 +9366,12 @@ const HTTP_REQUEST_TYPE = {
|
|
|
9319
9366
|
* Temporary cache keys for MSAL, deleted after any request.
|
|
9320
9367
|
*/
|
|
9321
9368
|
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
9369
|
ORIGIN_URI: "request.origin",
|
|
9328
|
-
RENEW_STATUS: "token.renew.status",
|
|
9329
9370
|
URL_HASH: "urlHash",
|
|
9330
9371
|
REQUEST_PARAMS: "request.params",
|
|
9331
|
-
|
|
9372
|
+
VERIFIER: "code.verifier",
|
|
9332
9373
|
INTERACTION_STATUS_KEY: "interaction.status",
|
|
9333
|
-
CCS_CREDENTIAL: "ccs.credential",
|
|
9334
|
-
CORRELATION_ID: "request.correlationId",
|
|
9335
9374
|
NATIVE_REQUEST: "request.native",
|
|
9336
|
-
REDIRECT_CONTEXT: "request.redirect.context",
|
|
9337
9375
|
};
|
|
9338
9376
|
const StaticCacheKeys = {
|
|
9339
9377
|
ACCOUNT_KEYS: "msal.account.keys",
|
|
@@ -9703,6 +9741,69 @@ async function importJwk(key, extractable, usages) {
|
|
|
9703
9741
|
async function sign(key, data) {
|
|
9704
9742
|
return window.crypto.subtle.sign(keygenAlgorithmOptions, key, data);
|
|
9705
9743
|
}
|
|
9744
|
+
/**
|
|
9745
|
+
* Generates Base64 encoded jwk used in the Encrypted Authorize Response (EAR) flow
|
|
9746
|
+
*/
|
|
9747
|
+
async function generateEarKey() {
|
|
9748
|
+
const key = await generateBaseKey();
|
|
9749
|
+
const keyStr = urlEncodeArr(new Uint8Array(key));
|
|
9750
|
+
const jwk = {
|
|
9751
|
+
alg: "dir",
|
|
9752
|
+
kty: "oct",
|
|
9753
|
+
k: keyStr,
|
|
9754
|
+
};
|
|
9755
|
+
return base64Encode(JSON.stringify(jwk));
|
|
9756
|
+
}
|
|
9757
|
+
/**
|
|
9758
|
+
* Parses earJwk for encryption key and returns CryptoKey object
|
|
9759
|
+
* @param earJwk
|
|
9760
|
+
* @returns
|
|
9761
|
+
*/
|
|
9762
|
+
async function importEarKey(earJwk) {
|
|
9763
|
+
const b64DecodedJwk = base64Decode(earJwk);
|
|
9764
|
+
const jwkJson = JSON.parse(b64DecodedJwk);
|
|
9765
|
+
const rawKey = jwkJson.k;
|
|
9766
|
+
const keyBuffer = base64DecToArr(rawKey);
|
|
9767
|
+
return window.crypto.subtle.importKey(RAW, keyBuffer, AES_GCM, false, [
|
|
9768
|
+
DECRYPT,
|
|
9769
|
+
]);
|
|
9770
|
+
}
|
|
9771
|
+
/**
|
|
9772
|
+
* Decrypt ear_jwe response returned in the Encrypted Authorize Response (EAR) flow
|
|
9773
|
+
* @param earJwk
|
|
9774
|
+
* @param earJwe
|
|
9775
|
+
* @returns
|
|
9776
|
+
*/
|
|
9777
|
+
async function decryptEarResponse(earJwk, earJwe) {
|
|
9778
|
+
const earJweParts = earJwe.split(".");
|
|
9779
|
+
if (earJweParts.length !== 5) {
|
|
9780
|
+
throw createBrowserAuthError(failedToDecryptEarResponse, "jwe_length");
|
|
9781
|
+
}
|
|
9782
|
+
const key = await importEarKey(earJwk).catch(() => {
|
|
9783
|
+
throw createBrowserAuthError(failedToDecryptEarResponse, "import_key");
|
|
9784
|
+
});
|
|
9785
|
+
try {
|
|
9786
|
+
const header = new TextEncoder().encode(earJweParts[0]);
|
|
9787
|
+
const iv = base64DecToArr(earJweParts[2]);
|
|
9788
|
+
const ciphertext = base64DecToArr(earJweParts[3]);
|
|
9789
|
+
const tag = base64DecToArr(earJweParts[4]);
|
|
9790
|
+
const tagLengthBits = tag.byteLength * 8;
|
|
9791
|
+
// Concat ciphertext and tag
|
|
9792
|
+
const encryptedData = new Uint8Array(ciphertext.length + tag.length);
|
|
9793
|
+
encryptedData.set(ciphertext);
|
|
9794
|
+
encryptedData.set(tag, ciphertext.length);
|
|
9795
|
+
const decryptedData = await window.crypto.subtle.decrypt({
|
|
9796
|
+
name: AES_GCM,
|
|
9797
|
+
iv: iv,
|
|
9798
|
+
tagLength: tagLengthBits,
|
|
9799
|
+
additionalData: header,
|
|
9800
|
+
}, key, encryptedData);
|
|
9801
|
+
return new TextDecoder().decode(decryptedData);
|
|
9802
|
+
}
|
|
9803
|
+
catch (e) {
|
|
9804
|
+
throw createBrowserAuthError(failedToDecryptEarResponse, "decrypt");
|
|
9805
|
+
}
|
|
9806
|
+
}
|
|
9706
9807
|
/**
|
|
9707
9808
|
* Generates symmetric base encryption key. This may be stored as all encryption/decryption keys will be derived from this one.
|
|
9708
9809
|
*/
|
|
@@ -10288,9 +10389,9 @@ function buildConfiguration({ auth: userInputAuth, cache: userInputCache, system
|
|
|
10288
10389
|
const logger = new Logger(providedSystemOptions.loggerOptions);
|
|
10289
10390
|
logger.warning(JSON.stringify(createClientConfigurationError(cannotSetOIDCOptions)));
|
|
10290
10391
|
}
|
|
10291
|
-
// Throw an error if user has set allowPlatformBroker to true
|
|
10392
|
+
// Throw an error if user has set allowPlatformBroker to true with OIDC protocol mode
|
|
10292
10393
|
if (userInputAuth?.protocolMode &&
|
|
10293
|
-
userInputAuth.protocolMode
|
|
10394
|
+
userInputAuth.protocolMode === ProtocolMode.OIDC &&
|
|
10294
10395
|
providedSystemOptions?.allowPlatformBroker) {
|
|
10295
10396
|
throw createClientConfigurationError(cannotAllowPlatformBroker);
|
|
10296
10397
|
}
|
|
@@ -10307,12 +10408,21 @@ function buildConfiguration({ auth: userInputAuth, cache: userInputCache, system
|
|
|
10307
10408
|
system: providedSystemOptions,
|
|
10308
10409
|
telemetry: { ...DEFAULT_TELEMETRY_OPTIONS, ...userInputTelemetry },
|
|
10309
10410
|
};
|
|
10411
|
+
/**
|
|
10412
|
+
* Temporarily disable EAR until implementation is complete
|
|
10413
|
+
* TODO: Remove this
|
|
10414
|
+
*/
|
|
10415
|
+
if (overlayedConfig.auth.protocolMode === ProtocolMode.EAR) {
|
|
10416
|
+
const logger = new Logger(providedSystemOptions.loggerOptions);
|
|
10417
|
+
logger.warning("EAR Protocol Mode is not yet supported. Overriding to use PKCE auth");
|
|
10418
|
+
overlayedConfig.auth.protocolMode = ProtocolMode.AAD;
|
|
10419
|
+
}
|
|
10310
10420
|
return overlayedConfig;
|
|
10311
10421
|
}
|
|
10312
10422
|
|
|
10313
10423
|
/* eslint-disable header/header */
|
|
10314
10424
|
const name = "@azure/msal-browser";
|
|
10315
|
-
const version = "4.
|
|
10425
|
+
const version = "4.9.0";
|
|
10316
10426
|
|
|
10317
10427
|
/*
|
|
10318
10428
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -11633,28 +11743,6 @@ class SessionStorage {
|
|
|
11633
11743
|
}
|
|
11634
11744
|
}
|
|
11635
11745
|
|
|
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
11746
|
/*
|
|
11659
11747
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
11660
11748
|
* Licensed under the MIT License.
|
|
@@ -12354,177 +12442,53 @@ class BrowserCacheManager extends CacheManager {
|
|
|
12354
12442
|
}
|
|
12355
12443
|
return JSON.stringify(key);
|
|
12356
12444
|
}
|
|
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
12445
|
/**
|
|
12426
12446
|
* Reset all temporary cache items
|
|
12427
12447
|
* @param state
|
|
12428
12448
|
*/
|
|
12429
|
-
resetRequestCache(
|
|
12449
|
+
resetRequestCache() {
|
|
12430
12450
|
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
12451
|
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.REQUEST_PARAMS));
|
|
12452
|
+
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.VERIFIER));
|
|
12444
12453
|
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.ORIGIN_URI));
|
|
12445
12454
|
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.URL_HASH));
|
|
12446
|
-
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.CORRELATION_ID));
|
|
12447
|
-
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.CCS_CREDENTIAL));
|
|
12448
12455
|
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST));
|
|
12449
12456
|
this.setInteractionInProgress(false);
|
|
12450
12457
|
}
|
|
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");
|
|
12458
|
+
cacheAuthorizeRequest(authCodeRequest, codeVerifier) {
|
|
12459
|
+
this.logger.trace("BrowserCacheManager.cacheAuthorizeRequest called");
|
|
12495
12460
|
const encodedValue = base64Encode(JSON.stringify(authCodeRequest));
|
|
12496
12461
|
this.setTemporaryCache(TemporaryCacheKeys.REQUEST_PARAMS, encodedValue, true);
|
|
12462
|
+
if (codeVerifier) {
|
|
12463
|
+
const encodedVerifier = base64Encode(codeVerifier);
|
|
12464
|
+
this.setTemporaryCache(TemporaryCacheKeys.VERIFIER, encodedVerifier, true);
|
|
12465
|
+
}
|
|
12497
12466
|
}
|
|
12498
12467
|
/**
|
|
12499
12468
|
* Gets the token exchange parameters from the cache. Throws an error if nothing is found.
|
|
12500
12469
|
*/
|
|
12501
|
-
getCachedRequest(
|
|
12470
|
+
getCachedRequest() {
|
|
12502
12471
|
this.logger.trace("BrowserCacheManager.getCachedRequest called");
|
|
12503
12472
|
// Get token request from cache and parse as TokenExchangeParameters.
|
|
12504
12473
|
const encodedTokenRequest = this.getTemporaryCache(TemporaryCacheKeys.REQUEST_PARAMS, true);
|
|
12505
12474
|
if (!encodedTokenRequest) {
|
|
12506
12475
|
throw createBrowserAuthError(noTokenRequestCacheError);
|
|
12507
12476
|
}
|
|
12477
|
+
const encodedVerifier = this.getTemporaryCache(TemporaryCacheKeys.VERIFIER, true);
|
|
12508
12478
|
let parsedRequest;
|
|
12479
|
+
let verifier = "";
|
|
12509
12480
|
try {
|
|
12510
12481
|
parsedRequest = JSON.parse(base64Decode(encodedTokenRequest));
|
|
12482
|
+
if (encodedVerifier) {
|
|
12483
|
+
verifier = base64Decode(encodedVerifier);
|
|
12484
|
+
}
|
|
12511
12485
|
}
|
|
12512
12486
|
catch (e) {
|
|
12513
12487
|
this.logger.errorPii(`Attempted to parse: ${encodedTokenRequest}`);
|
|
12514
12488
|
this.logger.error(`Parsing cached token request threw with error: ${e}`);
|
|
12515
12489
|
throw createBrowserAuthError(unableToParseTokenRequestCacheError);
|
|
12516
12490
|
}
|
|
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;
|
|
12491
|
+
return [parsedRequest, verifier];
|
|
12528
12492
|
}
|
|
12529
12493
|
/**
|
|
12530
12494
|
* Gets cached native request for redirect flows
|
|
@@ -13350,1083 +13314,1103 @@ function createNativeAuthError(code, description, ext) {
|
|
|
13350
13314
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13351
13315
|
* Licensed under the MIT License.
|
|
13352
13316
|
*/
|
|
13353
|
-
class
|
|
13317
|
+
class NativeMessageHandler {
|
|
13318
|
+
constructor(logger, handshakeTimeoutMs, performanceClient, extensionId) {
|
|
13319
|
+
this.logger = logger;
|
|
13320
|
+
this.handshakeTimeoutMs = handshakeTimeoutMs;
|
|
13321
|
+
this.extensionId = extensionId;
|
|
13322
|
+
this.resolvers = new Map(); // Used for non-handshake messages
|
|
13323
|
+
this.handshakeResolvers = new Map(); // Used for handshake messages
|
|
13324
|
+
this.messageChannel = new MessageChannel();
|
|
13325
|
+
this.windowListener = this.onWindowMessage.bind(this); // Window event callback doesn't have access to 'this' unless it's bound
|
|
13326
|
+
this.performanceClient = performanceClient;
|
|
13327
|
+
this.handshakeEvent = performanceClient.startMeasurement(PerformanceEvents.NativeMessageHandlerHandshake);
|
|
13328
|
+
}
|
|
13354
13329
|
/**
|
|
13355
|
-
*
|
|
13356
|
-
* @param
|
|
13330
|
+
* Sends a given message to the extension and resolves with the extension response
|
|
13331
|
+
* @param body
|
|
13357
13332
|
*/
|
|
13358
|
-
async
|
|
13359
|
-
this.
|
|
13360
|
-
|
|
13361
|
-
|
|
13362
|
-
|
|
13363
|
-
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
|
|
13333
|
+
async sendMessage(body) {
|
|
13334
|
+
this.logger.trace("NativeMessageHandler - sendMessage called.");
|
|
13335
|
+
const req = {
|
|
13336
|
+
channel: NativeConstants.CHANNEL_ID,
|
|
13337
|
+
extensionId: this.extensionId,
|
|
13338
|
+
responseId: createNewGuid(),
|
|
13339
|
+
body: body,
|
|
13340
|
+
};
|
|
13341
|
+
this.logger.trace("NativeMessageHandler - Sending request to browser extension");
|
|
13342
|
+
this.logger.tracePii(`NativeMessageHandler - Sending request to browser extension: ${JSON.stringify(req)}`);
|
|
13343
|
+
this.messageChannel.port1.postMessage(req);
|
|
13344
|
+
return new Promise((resolve, reject) => {
|
|
13345
|
+
this.resolvers.set(req.responseId, { resolve, reject });
|
|
13367
13346
|
});
|
|
13368
|
-
|
|
13369
|
-
|
|
13347
|
+
}
|
|
13348
|
+
/**
|
|
13349
|
+
* Returns an instance of the MessageHandler that has successfully established a connection with an extension
|
|
13350
|
+
* @param {Logger} logger
|
|
13351
|
+
* @param {number} handshakeTimeoutMs
|
|
13352
|
+
* @param {IPerformanceClient} performanceClient
|
|
13353
|
+
* @param {ICrypto} crypto
|
|
13354
|
+
*/
|
|
13355
|
+
static async createProvider(logger, handshakeTimeoutMs, performanceClient) {
|
|
13356
|
+
logger.trace("NativeMessageHandler - createProvider called.");
|
|
13370
13357
|
try {
|
|
13371
|
-
const
|
|
13372
|
-
|
|
13373
|
-
|
|
13374
|
-
fromCache: true,
|
|
13375
|
-
}, silentRequest.correlationId);
|
|
13376
|
-
return authResponse;
|
|
13358
|
+
const preferredProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient, NativeConstants.PREFERRED_EXTENSION_ID);
|
|
13359
|
+
await preferredProvider.sendHandshakeRequest();
|
|
13360
|
+
return preferredProvider;
|
|
13377
13361
|
}
|
|
13378
|
-
catch (
|
|
13379
|
-
|
|
13380
|
-
|
|
13381
|
-
|
|
13382
|
-
|
|
13383
|
-
throw error;
|
|
13362
|
+
catch (e) {
|
|
13363
|
+
// If preferred extension fails for whatever reason, fallback to using any installed extension
|
|
13364
|
+
const backupProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient);
|
|
13365
|
+
await backupProvider.sendHandshakeRequest();
|
|
13366
|
+
return backupProvider;
|
|
13384
13367
|
}
|
|
13385
13368
|
}
|
|
13386
13369
|
/**
|
|
13387
|
-
*
|
|
13388
|
-
* @param logoutRequest
|
|
13370
|
+
* Send handshake request helper.
|
|
13389
13371
|
*/
|
|
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(),
|
|
13372
|
+
async sendHandshakeRequest() {
|
|
13373
|
+
this.logger.trace("NativeMessageHandler - sendHandshakeRequest called.");
|
|
13374
|
+
// Register this event listener before sending handshake
|
|
13375
|
+
window.addEventListener("message", this.windowListener, false); // false is important, because content script message processing should work first
|
|
13376
|
+
const req = {
|
|
13377
|
+
channel: NativeConstants.CHANNEL_ID,
|
|
13378
|
+
extensionId: this.extensionId,
|
|
13379
|
+
responseId: createNewGuid(),
|
|
13380
|
+
body: {
|
|
13381
|
+
method: NativeExtensionMethod.HandshakeRequest,
|
|
13382
|
+
},
|
|
13383
|
+
};
|
|
13384
|
+
this.handshakeEvent.add({
|
|
13385
|
+
extensionId: this.extensionId,
|
|
13386
|
+
extensionHandshakeTimeoutMs: this.handshakeTimeoutMs,
|
|
13420
13387
|
});
|
|
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,
|
|
13388
|
+
this.messageChannel.port1.onmessage = (event) => {
|
|
13389
|
+
this.onChannelMessage(event);
|
|
13431
13390
|
};
|
|
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({
|
|
13391
|
+
window.postMessage(req, window.origin, [this.messageChannel.port2]);
|
|
13392
|
+
return new Promise((resolve, reject) => {
|
|
13393
|
+
this.handshakeResolvers.set(req.responseId, { resolve, reject });
|
|
13394
|
+
this.timeoutId = window.setTimeout(() => {
|
|
13395
|
+
/*
|
|
13396
|
+
* Throw an error if neither HandshakeResponse nor original Handshake request are received in a reasonable timeframe.
|
|
13397
|
+
* This typically suggests an event handler stopped propagation of the Handshake request but did not respond to it on the MessageChannel port
|
|
13398
|
+
*/
|
|
13399
|
+
window.removeEventListener("message", this.windowListener, false);
|
|
13400
|
+
this.messageChannel.port1.close();
|
|
13401
|
+
this.messageChannel.port2.close();
|
|
13402
|
+
this.handshakeEvent.end({
|
|
13403
|
+
extensionHandshakeTimedOut: true,
|
|
13485
13404
|
success: false,
|
|
13486
|
-
errorCode: error.errorCode,
|
|
13487
|
-
subErrorCode: error.subError,
|
|
13488
|
-
isNativeBroker: true,
|
|
13489
13405
|
});
|
|
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
|
-
};
|
|
13406
|
+
reject(createBrowserAuthError(nativeHandshakeTimeout));
|
|
13407
|
+
this.handshakeResolvers.delete(req.responseId);
|
|
13408
|
+
}, this.handshakeTimeoutMs); // Use a reasonable timeout in milliseconds here
|
|
13409
|
+
});
|
|
13514
13410
|
}
|
|
13515
13411
|
/**
|
|
13516
|
-
*
|
|
13517
|
-
* @param
|
|
13518
|
-
* @param request
|
|
13519
|
-
* @returns authenticationResult
|
|
13412
|
+
* Invoked when a message is posted to the window. If a handshake request is received it means the extension is not installed.
|
|
13413
|
+
* @param event
|
|
13520
13414
|
*/
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
|
|
13415
|
+
onWindowMessage(event) {
|
|
13416
|
+
this.logger.trace("NativeMessageHandler - onWindowMessage called");
|
|
13417
|
+
// We only accept messages from ourselves
|
|
13418
|
+
if (event.source !== window) {
|
|
13419
|
+
return;
|
|
13525
13420
|
}
|
|
13526
|
-
|
|
13527
|
-
|
|
13528
|
-
|
|
13529
|
-
|
|
13530
|
-
if (!account) {
|
|
13531
|
-
throw createClientAuthError(noAccountFound);
|
|
13421
|
+
const request = event.data;
|
|
13422
|
+
if (!request.channel ||
|
|
13423
|
+
request.channel !== NativeConstants.CHANNEL_ID) {
|
|
13424
|
+
return;
|
|
13532
13425
|
}
|
|
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
|
-
};
|
|
13426
|
+
if (request.extensionId && request.extensionId !== this.extensionId) {
|
|
13427
|
+
return;
|
|
13546
13428
|
}
|
|
13547
|
-
|
|
13548
|
-
|
|
13429
|
+
if (request.body.method === NativeExtensionMethod.HandshakeRequest) {
|
|
13430
|
+
const handshakeResolver = this.handshakeResolvers.get(request.responseId);
|
|
13431
|
+
/*
|
|
13432
|
+
* Filter out responses with no matched resolvers sooner to keep channel ports open while waiting for
|
|
13433
|
+
* the proper response.
|
|
13434
|
+
*/
|
|
13435
|
+
if (!handshakeResolver) {
|
|
13436
|
+
this.logger.trace(`NativeMessageHandler.onWindowMessage - resolver can't be found for request ${request.responseId}`);
|
|
13437
|
+
return;
|
|
13438
|
+
}
|
|
13439
|
+
// If we receive this message back it means no extension intercepted the request, meaning no extension supporting handshake protocol is installed
|
|
13440
|
+
this.logger.verbose(request.extensionId
|
|
13441
|
+
? `Extension with id: ${request.extensionId} not installed`
|
|
13442
|
+
: "No extension installed");
|
|
13443
|
+
clearTimeout(this.timeoutId);
|
|
13444
|
+
this.messageChannel.port1.close();
|
|
13445
|
+
this.messageChannel.port2.close();
|
|
13446
|
+
window.removeEventListener("message", this.windowListener, false);
|
|
13447
|
+
this.handshakeEvent.end({
|
|
13448
|
+
success: false,
|
|
13449
|
+
extensionInstalled: false,
|
|
13450
|
+
});
|
|
13451
|
+
handshakeResolver.reject(createBrowserAuthError(nativeExtensionNotInstalled));
|
|
13549
13452
|
}
|
|
13550
13453
|
}
|
|
13551
13454
|
/**
|
|
13552
|
-
*
|
|
13553
|
-
* @param
|
|
13554
|
-
* @param {InProgressPerformanceEvent} rootMeasurement
|
|
13455
|
+
* Invoked when a message is received from the extension on the MessageChannel port
|
|
13456
|
+
* @param event
|
|
13555
13457
|
*/
|
|
13556
|
-
|
|
13557
|
-
this.logger.trace("
|
|
13558
|
-
const
|
|
13559
|
-
|
|
13560
|
-
const
|
|
13561
|
-
const messageBody = {
|
|
13562
|
-
method: NativeExtensionMethod.GetToken,
|
|
13563
|
-
request: nativeRequest,
|
|
13564
|
-
};
|
|
13458
|
+
onChannelMessage(event) {
|
|
13459
|
+
this.logger.trace("NativeMessageHandler - onChannelMessage called.");
|
|
13460
|
+
const request = event.data;
|
|
13461
|
+
const resolver = this.resolvers.get(request.responseId);
|
|
13462
|
+
const handshakeResolver = this.handshakeResolvers.get(request.responseId);
|
|
13565
13463
|
try {
|
|
13566
|
-
const
|
|
13567
|
-
|
|
13568
|
-
|
|
13569
|
-
|
|
13570
|
-
|
|
13571
|
-
|
|
13572
|
-
|
|
13573
|
-
|
|
13574
|
-
if (
|
|
13575
|
-
|
|
13464
|
+
const method = request.body.method;
|
|
13465
|
+
if (method === NativeExtensionMethod.Response) {
|
|
13466
|
+
if (!resolver) {
|
|
13467
|
+
return;
|
|
13468
|
+
}
|
|
13469
|
+
const response = request.body.response;
|
|
13470
|
+
this.logger.trace("NativeMessageHandler - Received response from browser extension");
|
|
13471
|
+
this.logger.tracePii(`NativeMessageHandler - Received response from browser extension: ${JSON.stringify(response)}`);
|
|
13472
|
+
if (response.status !== "Success") {
|
|
13473
|
+
resolver.reject(createNativeAuthError(response.code, response.description, response.ext));
|
|
13474
|
+
}
|
|
13475
|
+
else if (response.result) {
|
|
13476
|
+
if (response.result["code"] &&
|
|
13477
|
+
response.result["description"]) {
|
|
13478
|
+
resolver.reject(createNativeAuthError(response.result["code"], response.result["description"], response.result["ext"]));
|
|
13479
|
+
}
|
|
13480
|
+
else {
|
|
13481
|
+
resolver.resolve(response.result);
|
|
13482
|
+
}
|
|
13483
|
+
}
|
|
13484
|
+
else {
|
|
13485
|
+
throw createAuthError(unexpectedError, "Event does not contain result.");
|
|
13576
13486
|
}
|
|
13487
|
+
this.resolvers.delete(request.responseId);
|
|
13488
|
+
}
|
|
13489
|
+
else if (method === NativeExtensionMethod.HandshakeResponse) {
|
|
13490
|
+
if (!handshakeResolver) {
|
|
13491
|
+
this.logger.trace(`NativeMessageHandler.onChannelMessage - resolver can't be found for request ${request.responseId}`);
|
|
13492
|
+
return;
|
|
13493
|
+
}
|
|
13494
|
+
clearTimeout(this.timeoutId); // Clear setTimeout
|
|
13495
|
+
window.removeEventListener("message", this.windowListener, false); // Remove 'No extension' listener
|
|
13496
|
+
this.extensionId = request.extensionId;
|
|
13497
|
+
this.extensionVersion = request.body.version;
|
|
13498
|
+
this.logger.verbose(`NativeMessageHandler - Received HandshakeResponse from extension: ${this.extensionId}`);
|
|
13499
|
+
this.handshakeEvent.end({
|
|
13500
|
+
extensionInstalled: true,
|
|
13501
|
+
success: true,
|
|
13502
|
+
});
|
|
13503
|
+
handshakeResolver.resolve();
|
|
13504
|
+
this.handshakeResolvers.delete(request.responseId);
|
|
13505
|
+
}
|
|
13506
|
+
// Do nothing if method is not Response or HandshakeResponse
|
|
13507
|
+
}
|
|
13508
|
+
catch (err) {
|
|
13509
|
+
this.logger.error("Error parsing response from WAM Extension");
|
|
13510
|
+
this.logger.errorPii(`Error parsing response from WAM Extension: ${err}`);
|
|
13511
|
+
this.logger.errorPii(`Unable to parse ${event}`);
|
|
13512
|
+
if (resolver) {
|
|
13513
|
+
resolver.reject(err);
|
|
13514
|
+
}
|
|
13515
|
+
else if (handshakeResolver) {
|
|
13516
|
+
handshakeResolver.reject(err);
|
|
13577
13517
|
}
|
|
13578
13518
|
}
|
|
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
13519
|
}
|
|
13591
13520
|
/**
|
|
13592
|
-
*
|
|
13593
|
-
* @
|
|
13594
|
-
* @param correlationId {string?} correlation identifier
|
|
13521
|
+
* Returns the Id for the browser extension this handler is communicating with
|
|
13522
|
+
* @returns
|
|
13595
13523
|
*/
|
|
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
|
-
}
|
|
13524
|
+
getExtensionId() {
|
|
13525
|
+
return this.extensionId;
|
|
13636
13526
|
}
|
|
13637
13527
|
/**
|
|
13638
|
-
*
|
|
13639
|
-
* @
|
|
13528
|
+
* Returns the version for the browser extension this handler is communicating with
|
|
13529
|
+
* @returns
|
|
13640
13530
|
*/
|
|
13641
|
-
|
|
13642
|
-
this.
|
|
13643
|
-
return Promise.reject("Logout not implemented yet");
|
|
13531
|
+
getExtensionVersion() {
|
|
13532
|
+
return this.extensionVersion;
|
|
13644
13533
|
}
|
|
13645
13534
|
/**
|
|
13646
|
-
*
|
|
13647
|
-
* @param
|
|
13648
|
-
* @param
|
|
13649
|
-
* @param
|
|
13535
|
+
* Returns boolean indicating whether or not the request should attempt to use native broker
|
|
13536
|
+
* @param logger
|
|
13537
|
+
* @param config
|
|
13538
|
+
* @param nativeExtensionProvider
|
|
13539
|
+
* @param authenticationScheme
|
|
13650
13540
|
*/
|
|
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");
|
|
13541
|
+
static isPlatformBrokerAvailable(config, logger, nativeExtensionProvider, authenticationScheme) {
|
|
13542
|
+
logger.trace("isPlatformBrokerAvailable called");
|
|
13543
|
+
if (!config.system.allowPlatformBroker) {
|
|
13544
|
+
logger.trace("isPlatformBrokerAvailable: allowPlatformBroker is not enabled, returning false");
|
|
13545
|
+
// Developer disabled WAM
|
|
13546
|
+
return false;
|
|
13663
13547
|
}
|
|
13664
|
-
|
|
13665
|
-
|
|
13666
|
-
//
|
|
13667
|
-
|
|
13548
|
+
if (!nativeExtensionProvider) {
|
|
13549
|
+
logger.trace("isPlatformBrokerAvailable: Platform extension provider is not initialized, returning false");
|
|
13550
|
+
// Extension is not available
|
|
13551
|
+
return false;
|
|
13668
13552
|
}
|
|
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;
|
|
13553
|
+
if (authenticationScheme) {
|
|
13554
|
+
switch (authenticationScheme) {
|
|
13555
|
+
case AuthenticationScheme.BEARER:
|
|
13556
|
+
case AuthenticationScheme.POP:
|
|
13557
|
+
logger.trace("isPlatformBrokerAvailable: authenticationScheme is supported, returning true");
|
|
13558
|
+
return true;
|
|
13559
|
+
default:
|
|
13560
|
+
logger.trace("isPlatformBrokerAvailable: authenticationScheme is not supported, returning false");
|
|
13561
|
+
return false;
|
|
13562
|
+
}
|
|
13563
|
+
}
|
|
13564
|
+
return true;
|
|
13684
13565
|
}
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13694
|
-
|
|
13566
|
+
}
|
|
13567
|
+
|
|
13568
|
+
/*
|
|
13569
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13570
|
+
* Licensed under the MIT License.
|
|
13571
|
+
*/
|
|
13572
|
+
/**
|
|
13573
|
+
* Extracts the BrowserStateObject from the state string.
|
|
13574
|
+
* @param browserCrypto
|
|
13575
|
+
* @param state
|
|
13576
|
+
*/
|
|
13577
|
+
function extractBrowserRequestState(browserCrypto, state) {
|
|
13578
|
+
if (!state) {
|
|
13579
|
+
return null;
|
|
13695
13580
|
}
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13705
|
-
|
|
13581
|
+
try {
|
|
13582
|
+
const requestStateObj = ProtocolUtils.parseRequestState(browserCrypto, state);
|
|
13583
|
+
return requestStateObj.libraryState.meta;
|
|
13584
|
+
}
|
|
13585
|
+
catch (e) {
|
|
13586
|
+
throw createClientAuthError(invalidState);
|
|
13587
|
+
}
|
|
13588
|
+
}
|
|
13589
|
+
|
|
13590
|
+
/*
|
|
13591
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13592
|
+
* Licensed under the MIT License.
|
|
13593
|
+
*/
|
|
13594
|
+
function deserializeResponse(responseString, responseLocation, logger) {
|
|
13595
|
+
// Deserialize hash fragment response parameters.
|
|
13596
|
+
const serverParams = getDeserializedResponse(responseString);
|
|
13597
|
+
if (!serverParams) {
|
|
13598
|
+
if (!stripLeadingHashOrQuery(responseString)) {
|
|
13599
|
+
// Hash or Query string is empty
|
|
13600
|
+
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.`);
|
|
13601
|
+
throw createBrowserAuthError(hashEmptyError);
|
|
13602
|
+
}
|
|
13603
|
+
else {
|
|
13604
|
+
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.`);
|
|
13605
|
+
logger.errorPii(`The ${responseLocation} detected is: ${responseString}`);
|
|
13606
|
+
throw createBrowserAuthError(hashDoesNotContainKnownProperties);
|
|
13607
|
+
}
|
|
13608
|
+
}
|
|
13609
|
+
return serverParams;
|
|
13610
|
+
}
|
|
13611
|
+
/**
|
|
13612
|
+
* Returns the interaction type that the response object belongs to
|
|
13613
|
+
*/
|
|
13614
|
+
function validateInteractionType(response, browserCrypto, interactionType) {
|
|
13615
|
+
if (!response.state) {
|
|
13616
|
+
throw createBrowserAuthError(noStateInHash);
|
|
13617
|
+
}
|
|
13618
|
+
const platformStateObj = extractBrowserRequestState(browserCrypto, response.state);
|
|
13619
|
+
if (!platformStateObj) {
|
|
13620
|
+
throw createBrowserAuthError(unableToParseState);
|
|
13621
|
+
}
|
|
13622
|
+
if (platformStateObj.interactionType !== interactionType) {
|
|
13623
|
+
throw createBrowserAuthError(stateInteractionTypeMismatch);
|
|
13624
|
+
}
|
|
13625
|
+
}
|
|
13626
|
+
|
|
13627
|
+
/*
|
|
13628
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13629
|
+
* Licensed under the MIT License.
|
|
13630
|
+
*/
|
|
13631
|
+
/**
|
|
13632
|
+
* Abstract class which defines operations for a browser interaction handling class.
|
|
13633
|
+
*/
|
|
13634
|
+
class InteractionHandler {
|
|
13635
|
+
constructor(authCodeModule, storageImpl, authCodeRequest, logger, performanceClient) {
|
|
13636
|
+
this.authModule = authCodeModule;
|
|
13637
|
+
this.browserStorage = storageImpl;
|
|
13638
|
+
this.authCodeRequest = authCodeRequest;
|
|
13639
|
+
this.logger = logger;
|
|
13640
|
+
this.performanceClient = performanceClient;
|
|
13706
13641
|
}
|
|
13707
13642
|
/**
|
|
13708
|
-
*
|
|
13709
|
-
* @param
|
|
13710
|
-
* @param response
|
|
13643
|
+
* Function to handle response parameters from hash.
|
|
13644
|
+
* @param locationHash
|
|
13711
13645
|
*/
|
|
13712
|
-
async
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13646
|
+
async handleCodeResponse(response, request) {
|
|
13647
|
+
this.performanceClient.addQueueMeasurement(PerformanceEvents.HandleCodeResponse, request.correlationId);
|
|
13648
|
+
let authCodeResponse;
|
|
13649
|
+
try {
|
|
13650
|
+
authCodeResponse = getAuthorizationCodePayload(response, request.state);
|
|
13651
|
+
}
|
|
13652
|
+
catch (e) {
|
|
13653
|
+
if (e instanceof ServerError &&
|
|
13654
|
+
e.subError === userCancelled) {
|
|
13655
|
+
// Translate server error caused by user closing native prompt to corresponding first class MSAL error
|
|
13656
|
+
throw createBrowserAuthError(userCancelled);
|
|
13723
13657
|
}
|
|
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);
|
|
13658
|
+
else {
|
|
13659
|
+
throw e;
|
|
13738
13660
|
}
|
|
13739
|
-
|
|
13661
|
+
}
|
|
13662
|
+
return invokeAsync(this.handleCodeResponseFromServer.bind(this), PerformanceEvents.HandleCodeResponseFromServer, this.logger, this.performanceClient, request.correlationId)(authCodeResponse, request);
|
|
13663
|
+
}
|
|
13664
|
+
/**
|
|
13665
|
+
* Process auth code response from AAD
|
|
13666
|
+
* @param authCodeResponse
|
|
13667
|
+
* @param state
|
|
13668
|
+
* @param authority
|
|
13669
|
+
* @param networkModule
|
|
13670
|
+
* @returns
|
|
13671
|
+
*/
|
|
13672
|
+
async handleCodeResponseFromServer(authCodeResponse, request, validateNonce = true) {
|
|
13673
|
+
this.performanceClient.addQueueMeasurement(PerformanceEvents.HandleCodeResponseFromServer, request.correlationId);
|
|
13674
|
+
this.logger.trace("InteractionHandler.handleCodeResponseFromServer called");
|
|
13675
|
+
// Assign code to request
|
|
13676
|
+
this.authCodeRequest.code = authCodeResponse.code;
|
|
13677
|
+
// Check for new cloud instance
|
|
13678
|
+
if (authCodeResponse.cloud_instance_host_name) {
|
|
13679
|
+
await invokeAsync(this.authModule.updateAuthority.bind(this.authModule), PerformanceEvents.UpdateTokenEndpointAuthority, this.logger, this.performanceClient, request.correlationId)(authCodeResponse.cloud_instance_host_name, request.correlationId);
|
|
13680
|
+
}
|
|
13681
|
+
// Nonce validation not needed when redirect not involved (e.g. hybrid spa, renewing token via rt)
|
|
13682
|
+
if (validateNonce) {
|
|
13683
|
+
// TODO: Assigning "response nonce" to "request nonce" is confusing. Refactor the function doing validation to accept request nonce directly
|
|
13684
|
+
authCodeResponse.nonce = request.nonce || undefined;
|
|
13685
|
+
}
|
|
13686
|
+
authCodeResponse.state = request.state;
|
|
13687
|
+
// Add CCS parameters if available
|
|
13688
|
+
if (authCodeResponse.client_info) {
|
|
13689
|
+
this.authCodeRequest.clientInfo = authCodeResponse.client_info;
|
|
13740
13690
|
}
|
|
13741
13691
|
else {
|
|
13742
|
-
|
|
13692
|
+
const ccsCred = this.createCcsCredentials(request);
|
|
13693
|
+
if (ccsCred) {
|
|
13694
|
+
this.authCodeRequest.ccsCredential = ccsCred;
|
|
13695
|
+
}
|
|
13743
13696
|
}
|
|
13697
|
+
// Acquire token with retrieved code.
|
|
13698
|
+
const tokenResponse = (await invokeAsync(this.authModule.acquireToken.bind(this.authModule), PerformanceEvents.AuthClientAcquireToken, this.logger, this.performanceClient, request.correlationId)(this.authCodeRequest, authCodeResponse));
|
|
13699
|
+
return tokenResponse;
|
|
13744
13700
|
}
|
|
13745
13701
|
/**
|
|
13746
|
-
*
|
|
13747
|
-
* @param response
|
|
13748
|
-
* @param request
|
|
13749
|
-
* @param idTokenObj
|
|
13750
|
-
* @param accountEntity
|
|
13751
|
-
* @param authority
|
|
13752
|
-
* @param reqTimestamp
|
|
13753
|
-
* @returns
|
|
13702
|
+
* Build ccs creds if available
|
|
13754
13703
|
*/
|
|
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;
|
|
13704
|
+
createCcsCredentials(request) {
|
|
13705
|
+
if (request.account) {
|
|
13706
|
+
return {
|
|
13707
|
+
credential: request.account.homeAccountId,
|
|
13708
|
+
type: CcsCredentialType.HOME_ACCOUNT_ID,
|
|
13709
|
+
};
|
|
13778
13710
|
}
|
|
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;
|
|
13711
|
+
else if (request.loginHint) {
|
|
13712
|
+
return {
|
|
13713
|
+
credential: request.loginHint,
|
|
13714
|
+
type: CcsCredentialType.UPN,
|
|
13715
|
+
};
|
|
13716
|
+
}
|
|
13717
|
+
return null;
|
|
13802
13718
|
}
|
|
13719
|
+
}
|
|
13720
|
+
|
|
13721
|
+
/*
|
|
13722
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13723
|
+
* Licensed under the MIT License.
|
|
13724
|
+
*/
|
|
13725
|
+
class SilentCacheClient extends StandardInteractionClient {
|
|
13803
13726
|
/**
|
|
13804
|
-
*
|
|
13805
|
-
* @param
|
|
13727
|
+
* Returns unexpired tokens from the cache, if available
|
|
13728
|
+
* @param silentRequest
|
|
13806
13729
|
*/
|
|
13807
|
-
async
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
this.
|
|
13812
|
-
|
|
13730
|
+
async acquireToken(silentRequest) {
|
|
13731
|
+
this.performanceClient.addQueueMeasurement(PerformanceEvents.SilentCacheClientAcquireToken, silentRequest.correlationId);
|
|
13732
|
+
// Telemetry manager only used to increment cacheHits here
|
|
13733
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenSilent_silentFlow);
|
|
13734
|
+
const clientConfig = await invokeAsync(this.getClientConfiguration.bind(this), PerformanceEvents.StandardInteractionClientGetClientConfiguration, this.logger, this.performanceClient, this.correlationId)({
|
|
13735
|
+
serverTelemetryManager,
|
|
13736
|
+
requestAuthority: silentRequest.authority,
|
|
13737
|
+
requestAzureCloudOptions: silentRequest.azureCloudOptions,
|
|
13738
|
+
account: silentRequest.account,
|
|
13813
13739
|
});
|
|
13740
|
+
const silentAuthClient = new SilentFlowClient(clientConfig, this.performanceClient);
|
|
13741
|
+
this.logger.verbose("Silent auth client created");
|
|
13742
|
+
try {
|
|
13743
|
+
const response = await invokeAsync(silentAuthClient.acquireCachedToken.bind(silentAuthClient), PerformanceEvents.SilentFlowClientAcquireCachedToken, this.logger, this.performanceClient, silentRequest.correlationId)(silentRequest);
|
|
13744
|
+
const authResponse = response[0];
|
|
13745
|
+
this.performanceClient.addFields({
|
|
13746
|
+
fromCache: true,
|
|
13747
|
+
}, silentRequest.correlationId);
|
|
13748
|
+
return authResponse;
|
|
13749
|
+
}
|
|
13750
|
+
catch (error) {
|
|
13751
|
+
if (error instanceof BrowserAuthError &&
|
|
13752
|
+
error.errorCode === cryptoKeyNotFound) {
|
|
13753
|
+
this.logger.verbose("Signing keypair for bound access token not found. Refreshing bound access token and generating a new crypto keypair.");
|
|
13754
|
+
}
|
|
13755
|
+
throw error;
|
|
13756
|
+
}
|
|
13814
13757
|
}
|
|
13815
13758
|
/**
|
|
13816
|
-
*
|
|
13817
|
-
* @param
|
|
13818
|
-
* @param request
|
|
13819
|
-
* @param homeAccountIdentifier
|
|
13820
|
-
* @param idTokenObj
|
|
13821
|
-
* @param responseAccessToken
|
|
13822
|
-
* @param tenantId
|
|
13823
|
-
* @param reqTimestamp
|
|
13759
|
+
* API to silenty clear the browser cache.
|
|
13760
|
+
* @param logoutRequest
|
|
13824
13761
|
*/
|
|
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);
|
|
13762
|
+
logout(logoutRequest) {
|
|
13763
|
+
this.logger.verbose("logoutRedirect called");
|
|
13764
|
+
const validLogoutRequest = this.initializeLogoutRequest(logoutRequest);
|
|
13765
|
+
return this.clearCacheOnLogout(validLogoutRequest?.account);
|
|
13841
13766
|
}
|
|
13842
|
-
|
|
13843
|
-
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13767
|
+
}
|
|
13768
|
+
|
|
13769
|
+
/*
|
|
13770
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13771
|
+
* Licensed under the MIT License.
|
|
13772
|
+
*/
|
|
13773
|
+
class NativeInteractionClient extends BaseInteractionClient {
|
|
13774
|
+
constructor(config, browserStorage, browserCrypto, logger, eventHandler, navigationClient, apiId, performanceClient, provider, accountId, nativeStorageImpl, correlationId) {
|
|
13775
|
+
super(config, browserStorage, browserCrypto, logger, eventHandler, navigationClient, performanceClient, provider, correlationId);
|
|
13776
|
+
this.apiId = apiId;
|
|
13777
|
+
this.accountId = accountId;
|
|
13778
|
+
this.nativeMessageHandler = provider;
|
|
13779
|
+
this.nativeStorageManager = nativeStorageImpl;
|
|
13780
|
+
this.silentCacheClient = new SilentCacheClient(config, this.nativeStorageManager, browserCrypto, logger, eventHandler, navigationClient, performanceClient, provider, correlationId);
|
|
13781
|
+
const extensionName = this.nativeMessageHandler.getExtensionId() ===
|
|
13782
|
+
NativeConstants.PREFERRED_EXTENSION_ID
|
|
13783
|
+
? "chrome"
|
|
13784
|
+
: this.nativeMessageHandler.getExtensionId()?.length
|
|
13785
|
+
? "unknown"
|
|
13786
|
+
: undefined;
|
|
13787
|
+
this.skus = ServerTelemetryManager.makeExtraSkuString({
|
|
13788
|
+
libraryName: BrowserConstants.MSAL_SKU,
|
|
13789
|
+
libraryVersion: version,
|
|
13790
|
+
extensionName: extensionName,
|
|
13849
13791
|
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;
|
|
13792
|
+
});
|
|
13865
13793
|
}
|
|
13866
13794
|
/**
|
|
13867
|
-
*
|
|
13868
|
-
* @param
|
|
13795
|
+
* Adds SKUs to request extra query parameters
|
|
13796
|
+
* @param request {NativeTokenRequest}
|
|
13797
|
+
* @private
|
|
13869
13798
|
*/
|
|
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
|
-
}
|
|
13799
|
+
addRequestSKUs(request) {
|
|
13800
|
+
request.extraParameters = {
|
|
13801
|
+
...request.extraParameters,
|
|
13802
|
+
[X_CLIENT_EXTRA_SKU]: this.skus,
|
|
13803
|
+
};
|
|
13882
13804
|
}
|
|
13883
13805
|
/**
|
|
13884
|
-
*
|
|
13885
|
-
* @param
|
|
13886
|
-
* @returns
|
|
13806
|
+
* Acquire token from native platform via browser extension
|
|
13807
|
+
* @param request
|
|
13887
13808
|
*/
|
|
13888
|
-
|
|
13889
|
-
|
|
13809
|
+
async acquireToken(request, cacheLookupPolicy) {
|
|
13810
|
+
this.performanceClient.addQueueMeasurement(PerformanceEvents.NativeInteractionClientAcquireToken, request.correlationId);
|
|
13811
|
+
this.logger.trace("NativeInteractionClient - acquireToken called.");
|
|
13812
|
+
// start the perf measurement
|
|
13813
|
+
const nativeATMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.NativeInteractionClientAcquireToken, request.correlationId);
|
|
13814
|
+
const reqTimestamp = nowSeconds();
|
|
13815
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
13816
|
+
try {
|
|
13817
|
+
// initialize native request
|
|
13818
|
+
const nativeRequest = await this.initializeNativeRequest(request);
|
|
13819
|
+
// check if the tokens can be retrieved from internal cache
|
|
13890
13820
|
try {
|
|
13891
|
-
|
|
13821
|
+
const result = await this.acquireTokensFromCache(this.accountId, nativeRequest);
|
|
13822
|
+
nativeATMeasurement.end({
|
|
13823
|
+
success: true,
|
|
13824
|
+
isNativeBroker: false,
|
|
13825
|
+
fromCache: true,
|
|
13826
|
+
});
|
|
13827
|
+
return result;
|
|
13892
13828
|
}
|
|
13893
13829
|
catch (e) {
|
|
13894
|
-
|
|
13830
|
+
if (cacheLookupPolicy === CacheLookupPolicy.AccessToken) {
|
|
13831
|
+
this.logger.info("MSAL internal Cache does not contain tokens, return error as per cache policy");
|
|
13832
|
+
throw e;
|
|
13833
|
+
}
|
|
13834
|
+
// continue with a native call for any and all errors
|
|
13835
|
+
this.logger.info("MSAL internal Cache does not contain tokens, proceed to make a native call");
|
|
13895
13836
|
}
|
|
13837
|
+
const { ...nativeTokenRequest } = nativeRequest;
|
|
13838
|
+
// fall back to native calls
|
|
13839
|
+
const messageBody = {
|
|
13840
|
+
method: NativeExtensionMethod.GetToken,
|
|
13841
|
+
request: nativeTokenRequest,
|
|
13842
|
+
};
|
|
13843
|
+
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
13844
|
+
const validatedResponse = this.validateNativeResponse(response);
|
|
13845
|
+
return await this.handleNativeResponse(validatedResponse, nativeRequest, reqTimestamp)
|
|
13846
|
+
.then((result) => {
|
|
13847
|
+
nativeATMeasurement.end({
|
|
13848
|
+
success: true,
|
|
13849
|
+
isNativeBroker: true,
|
|
13850
|
+
requestId: result.requestId,
|
|
13851
|
+
});
|
|
13852
|
+
serverTelemetryManager.clearNativeBrokerErrorCode();
|
|
13853
|
+
return result;
|
|
13854
|
+
})
|
|
13855
|
+
.catch((error) => {
|
|
13856
|
+
nativeATMeasurement.end({
|
|
13857
|
+
success: false,
|
|
13858
|
+
errorCode: error.errorCode,
|
|
13859
|
+
subErrorCode: error.subError,
|
|
13860
|
+
isNativeBroker: true,
|
|
13861
|
+
});
|
|
13862
|
+
throw error;
|
|
13863
|
+
});
|
|
13896
13864
|
}
|
|
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;
|
|
13865
|
+
catch (e) {
|
|
13866
|
+
if (e instanceof NativeAuthError) {
|
|
13867
|
+
serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode);
|
|
13868
|
+
}
|
|
13869
|
+
throw e;
|
|
13908
13870
|
}
|
|
13909
|
-
return !!mats.is_cached;
|
|
13910
13871
|
}
|
|
13911
13872
|
/**
|
|
13912
|
-
*
|
|
13873
|
+
* Creates silent flow request
|
|
13913
13874
|
* @param request
|
|
13875
|
+
* @param cachedAccount
|
|
13876
|
+
* @returns CommonSilentFlowRequest
|
|
13914
13877
|
*/
|
|
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(),
|
|
13878
|
+
createSilentCacheRequest(request, cachedAccount) {
|
|
13879
|
+
return {
|
|
13880
|
+
authority: request.authority,
|
|
13965
13881
|
correlationId: this.correlationId,
|
|
13966
|
-
|
|
13967
|
-
|
|
13968
|
-
|
|
13969
|
-
...request.extraQueryParameters,
|
|
13970
|
-
...request.tokenQueryParameters,
|
|
13971
|
-
},
|
|
13972
|
-
extendedExpiryToken: false,
|
|
13973
|
-
keyId: request.popKid,
|
|
13882
|
+
scopes: ScopeSet.fromString(request.scope).asArray(),
|
|
13883
|
+
account: cachedAccount,
|
|
13884
|
+
forceRefresh: false,
|
|
13974
13885
|
};
|
|
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
13886
|
}
|
|
14011
13887
|
/**
|
|
14012
|
-
*
|
|
14013
|
-
* @param
|
|
14014
|
-
* @
|
|
13888
|
+
* Fetches the tokens from the cache if un-expired
|
|
13889
|
+
* @param nativeAccountId
|
|
13890
|
+
* @param request
|
|
13891
|
+
* @returns authenticationResult
|
|
14015
13892
|
*/
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
|
|
14019
|
-
|
|
14020
|
-
request.extraParameters.hasOwnProperty(CLIENT_ID);
|
|
14021
|
-
if (!request.embeddedClientId && !hasExtraBrokerParams) {
|
|
14022
|
-
return;
|
|
13893
|
+
async acquireTokensFromCache(nativeAccountId, request) {
|
|
13894
|
+
if (!nativeAccountId) {
|
|
13895
|
+
this.logger.warning("NativeInteractionClient:acquireTokensFromCache - No nativeAccountId provided");
|
|
13896
|
+
throw createClientAuthError(noAccountFound);
|
|
14023
13897
|
}
|
|
14024
|
-
|
|
14025
|
-
const
|
|
14026
|
-
|
|
14027
|
-
|
|
14028
|
-
|
|
13898
|
+
// fetch the account from browser cache
|
|
13899
|
+
const account = this.browserStorage.getBaseAccountInfo({
|
|
13900
|
+
nativeAccountId,
|
|
13901
|
+
});
|
|
13902
|
+
if (!account) {
|
|
13903
|
+
throw createClientAuthError(noAccountFound);
|
|
14029
13904
|
}
|
|
14030
|
-
|
|
14031
|
-
|
|
14032
|
-
|
|
14033
|
-
|
|
14034
|
-
|
|
13905
|
+
// leverage silent flow for cached tokens retrieval
|
|
13906
|
+
try {
|
|
13907
|
+
const silentRequest = this.createSilentCacheRequest(request, account);
|
|
13908
|
+
const result = await this.silentCacheClient.acquireToken(silentRequest);
|
|
13909
|
+
const fullAccount = {
|
|
13910
|
+
...account,
|
|
13911
|
+
idTokenClaims: result?.idTokenClaims,
|
|
13912
|
+
idToken: result?.idToken,
|
|
13913
|
+
};
|
|
13914
|
+
return {
|
|
13915
|
+
...result,
|
|
13916
|
+
account: fullAccount,
|
|
13917
|
+
};
|
|
13918
|
+
}
|
|
13919
|
+
catch (e) {
|
|
13920
|
+
throw e;
|
|
14035
13921
|
}
|
|
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
13922
|
}
|
|
14063
13923
|
/**
|
|
14064
|
-
*
|
|
14065
|
-
* @param
|
|
13924
|
+
* Acquires a token from native platform then redirects to the redirectUri instead of returning the response
|
|
13925
|
+
* @param {RedirectRequest} request
|
|
13926
|
+
* @param {InProgressPerformanceEvent} rootMeasurement
|
|
14066
13927
|
*/
|
|
14067
|
-
async
|
|
14068
|
-
this.logger.trace("
|
|
14069
|
-
const
|
|
14070
|
-
|
|
14071
|
-
|
|
14072
|
-
|
|
14073
|
-
|
|
13928
|
+
async acquireTokenRedirect(request, rootMeasurement) {
|
|
13929
|
+
this.logger.trace("NativeInteractionClient - acquireTokenRedirect called.");
|
|
13930
|
+
const { ...remainingParameters } = request;
|
|
13931
|
+
delete remainingParameters.onRedirectNavigate;
|
|
13932
|
+
const nativeRequest = await this.initializeNativeRequest(remainingParameters);
|
|
13933
|
+
const messageBody = {
|
|
13934
|
+
method: NativeExtensionMethod.GetToken,
|
|
13935
|
+
request: nativeRequest,
|
|
14074
13936
|
};
|
|
14075
|
-
|
|
14076
|
-
|
|
14077
|
-
|
|
14078
|
-
|
|
14079
|
-
|
|
14080
|
-
|
|
13937
|
+
try {
|
|
13938
|
+
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
13939
|
+
this.validateNativeResponse(response);
|
|
13940
|
+
}
|
|
13941
|
+
catch (e) {
|
|
13942
|
+
// Only throw fatal errors here to allow application to fallback to regular redirect. Otherwise proceed and the error will be thrown in handleRedirectPromise
|
|
13943
|
+
if (e instanceof NativeAuthError) {
|
|
13944
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
13945
|
+
serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode);
|
|
13946
|
+
if (isFatalNativeAuthError(e)) {
|
|
13947
|
+
throw e;
|
|
13948
|
+
}
|
|
13949
|
+
}
|
|
13950
|
+
}
|
|
13951
|
+
this.browserStorage.setTemporaryCache(TemporaryCacheKeys.NATIVE_REQUEST, JSON.stringify(nativeRequest), true);
|
|
13952
|
+
const navigationOptions = {
|
|
13953
|
+
apiId: ApiId.acquireTokenRedirect,
|
|
13954
|
+
timeout: this.config.system.redirectNavigationTimeout,
|
|
13955
|
+
noHistory: false,
|
|
13956
|
+
};
|
|
13957
|
+
const redirectUri = this.config.auth.navigateToLoginRequestUrl
|
|
13958
|
+
? window.location.href
|
|
13959
|
+
: this.getRedirectUri(request.redirectUri);
|
|
13960
|
+
rootMeasurement.end({ success: true });
|
|
13961
|
+
await this.navigationClient.navigateExternal(redirectUri, navigationOptions); // Need to treat this as external to ensure handleRedirectPromise is run again
|
|
14081
13962
|
}
|
|
14082
13963
|
/**
|
|
14083
|
-
*
|
|
14084
|
-
* @param {
|
|
14085
|
-
* @param {
|
|
14086
|
-
* @param {IPerformanceClient} performanceClient
|
|
14087
|
-
* @param {ICrypto} crypto
|
|
13964
|
+
* If the previous page called native platform for a token using redirect APIs, send the same request again and return the response
|
|
13965
|
+
* @param performanceClient {IPerformanceClient?}
|
|
13966
|
+
* @param correlationId {string?} correlation identifier
|
|
14088
13967
|
*/
|
|
14089
|
-
|
|
14090
|
-
logger.trace("
|
|
13968
|
+
async handleRedirectPromise(performanceClient, correlationId) {
|
|
13969
|
+
this.logger.trace("NativeInteractionClient - handleRedirectPromise called.");
|
|
13970
|
+
if (!this.browserStorage.isInteractionInProgress(true)) {
|
|
13971
|
+
this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
|
|
13972
|
+
return null;
|
|
13973
|
+
}
|
|
13974
|
+
// remove prompt from the request to prevent WAM from prompting twice
|
|
13975
|
+
const cachedRequest = this.browserStorage.getCachedNativeRequest();
|
|
13976
|
+
if (!cachedRequest) {
|
|
13977
|
+
this.logger.verbose("NativeInteractionClient - handleRedirectPromise called but there is no cached request, returning null.");
|
|
13978
|
+
if (performanceClient && correlationId) {
|
|
13979
|
+
performanceClient?.addFields({ errorCode: "no_cached_request" }, correlationId);
|
|
13980
|
+
}
|
|
13981
|
+
return null;
|
|
13982
|
+
}
|
|
13983
|
+
const { prompt, ...request } = cachedRequest;
|
|
13984
|
+
if (prompt) {
|
|
13985
|
+
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.");
|
|
13986
|
+
}
|
|
13987
|
+
this.browserStorage.removeItem(this.browserStorage.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST));
|
|
13988
|
+
const messageBody = {
|
|
13989
|
+
method: NativeExtensionMethod.GetToken,
|
|
13990
|
+
request: request,
|
|
13991
|
+
};
|
|
13992
|
+
const reqTimestamp = nowSeconds();
|
|
14091
13993
|
try {
|
|
14092
|
-
|
|
14093
|
-
await
|
|
14094
|
-
|
|
13994
|
+
this.logger.verbose("NativeInteractionClient - handleRedirectPromise sending message to native broker.");
|
|
13995
|
+
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
13996
|
+
this.validateNativeResponse(response);
|
|
13997
|
+
const result = this.handleNativeResponse(response, request, reqTimestamp);
|
|
13998
|
+
const res = await result;
|
|
13999
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
14000
|
+
serverTelemetryManager.clearNativeBrokerErrorCode();
|
|
14001
|
+
return res;
|
|
14095
14002
|
}
|
|
14096
14003
|
catch (e) {
|
|
14097
|
-
|
|
14098
|
-
const backupProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient);
|
|
14099
|
-
await backupProvider.sendHandshakeRequest();
|
|
14100
|
-
return backupProvider;
|
|
14004
|
+
throw e;
|
|
14101
14005
|
}
|
|
14102
14006
|
}
|
|
14103
14007
|
/**
|
|
14104
|
-
*
|
|
14008
|
+
* Logout from native platform via browser extension
|
|
14009
|
+
* @param request
|
|
14105
14010
|
*/
|
|
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
|
-
});
|
|
14011
|
+
logout() {
|
|
14012
|
+
this.logger.trace("NativeInteractionClient - logout called.");
|
|
14013
|
+
return Promise.reject("Logout not implemented yet");
|
|
14144
14014
|
}
|
|
14145
14015
|
/**
|
|
14146
|
-
*
|
|
14147
|
-
* @param
|
|
14016
|
+
* Transform response from native platform into AuthenticationResult object which will be returned to the end user
|
|
14017
|
+
* @param response
|
|
14018
|
+
* @param request
|
|
14019
|
+
* @param reqTimestamp
|
|
14148
14020
|
*/
|
|
14149
|
-
|
|
14150
|
-
this.logger.trace("
|
|
14151
|
-
//
|
|
14152
|
-
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
|
|
14156
|
-
|
|
14157
|
-
|
|
14158
|
-
|
|
14159
|
-
|
|
14160
|
-
|
|
14161
|
-
return;
|
|
14021
|
+
async handleNativeResponse(response, request, reqTimestamp) {
|
|
14022
|
+
this.logger.trace("NativeInteractionClient - handleNativeResponse called.");
|
|
14023
|
+
// generate identifiers
|
|
14024
|
+
const idTokenClaims = extractTokenClaims(response.id_token, base64Decode);
|
|
14025
|
+
const homeAccountIdentifier = this.createHomeAccountIdentifier(response, idTokenClaims);
|
|
14026
|
+
const cachedhomeAccountId = this.browserStorage.getAccountInfoFilteredBy({
|
|
14027
|
+
nativeAccountId: request.accountId,
|
|
14028
|
+
})?.homeAccountId;
|
|
14029
|
+
// add exception for double brokering, please note this is temporary and will be fortified in future
|
|
14030
|
+
if (request.extraParameters?.child_client_id &&
|
|
14031
|
+
response.account.id !== request.accountId) {
|
|
14032
|
+
this.logger.info("handleNativeServerResponse: Double broker flow detected, ignoring accountId mismatch");
|
|
14162
14033
|
}
|
|
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));
|
|
14034
|
+
else if (homeAccountIdentifier !== cachedhomeAccountId &&
|
|
14035
|
+
response.account.id !== request.accountId) {
|
|
14036
|
+
// 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
|
|
14037
|
+
throw createNativeAuthError(userSwitch);
|
|
14186
14038
|
}
|
|
14039
|
+
// Get the preferred_cache domain for the given authority
|
|
14040
|
+
const authority = await this.getDiscoveredAuthority({
|
|
14041
|
+
requestAuthority: request.authority,
|
|
14042
|
+
});
|
|
14043
|
+
const baseAccount = buildAccountToCache(this.browserStorage, authority, homeAccountIdentifier, base64Decode, idTokenClaims, response.client_info, undefined, // environment
|
|
14044
|
+
idTokenClaims.tid, undefined, // auth code payload
|
|
14045
|
+
response.account.id, this.logger);
|
|
14046
|
+
// Ensure expires_in is in number format
|
|
14047
|
+
response.expires_in = Number(response.expires_in);
|
|
14048
|
+
// generate authenticationResult
|
|
14049
|
+
const result = await this.generateAuthenticationResult(response, request, idTokenClaims, baseAccount, authority.canonicalAuthority, reqTimestamp);
|
|
14050
|
+
// cache accounts and tokens in the appropriate storage
|
|
14051
|
+
await this.cacheAccount(baseAccount);
|
|
14052
|
+
await this.cacheNativeTokens(response, request, homeAccountIdentifier, idTokenClaims, response.access_token, result.tenantId, reqTimestamp);
|
|
14053
|
+
return result;
|
|
14187
14054
|
}
|
|
14188
14055
|
/**
|
|
14189
|
-
*
|
|
14190
|
-
* @param
|
|
14056
|
+
* creates an homeAccountIdentifier for the account
|
|
14057
|
+
* @param response
|
|
14058
|
+
* @param idTokenObj
|
|
14059
|
+
* @returns
|
|
14191
14060
|
*/
|
|
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
|
-
|
|
14061
|
+
createHomeAccountIdentifier(response, idTokenClaims) {
|
|
14062
|
+
// Save account in browser storage
|
|
14063
|
+
const homeAccountIdentifier = AccountEntity.generateHomeAccountId(response.client_info || Constants.EMPTY_STRING, AuthorityType.Default, this.logger, this.browserCrypto, idTokenClaims);
|
|
14064
|
+
return homeAccountIdentifier;
|
|
14065
|
+
}
|
|
14066
|
+
/**
|
|
14067
|
+
* Helper to generate scopes
|
|
14068
|
+
* @param response
|
|
14069
|
+
* @param request
|
|
14070
|
+
* @returns
|
|
14071
|
+
*/
|
|
14072
|
+
generateScopes(response, request) {
|
|
14073
|
+
return response.scope
|
|
14074
|
+
? ScopeSet.fromString(response.scope)
|
|
14075
|
+
: ScopeSet.fromString(request.scope);
|
|
14076
|
+
}
|
|
14077
|
+
/**
|
|
14078
|
+
* If PoP token is requesred, records the PoP token if returned from the WAM, else generates one in the browser
|
|
14079
|
+
* @param request
|
|
14080
|
+
* @param response
|
|
14081
|
+
*/
|
|
14082
|
+
async generatePopAccessToken(response, request) {
|
|
14083
|
+
if (request.tokenType === AuthenticationScheme.POP &&
|
|
14084
|
+
request.signPopToken) {
|
|
14085
|
+
/**
|
|
14086
|
+
* This code prioritizes SHR returned from the native layer. In case of error/SHR not calculated from WAM and the AT
|
|
14087
|
+
* is still received, SHR is calculated locally
|
|
14088
|
+
*/
|
|
14089
|
+
// Check if native layer returned an SHR token
|
|
14090
|
+
if (response.shr) {
|
|
14091
|
+
this.logger.trace("handleNativeServerResponse: SHR is enabled in native layer");
|
|
14092
|
+
return response.shr;
|
|
14222
14093
|
}
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
handshakeResolver.resolve();
|
|
14238
|
-
this.handshakeResolvers.delete(request.responseId);
|
|
14094
|
+
// Generate SHR in msal js if WAM does not compute it when POP is enabled
|
|
14095
|
+
const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);
|
|
14096
|
+
const shrParameters = {
|
|
14097
|
+
resourceRequestMethod: request.resourceRequestMethod,
|
|
14098
|
+
resourceRequestUri: request.resourceRequestUri,
|
|
14099
|
+
shrClaims: request.shrClaims,
|
|
14100
|
+
shrNonce: request.shrNonce,
|
|
14101
|
+
};
|
|
14102
|
+
/**
|
|
14103
|
+
* KeyID must be present in the native request from when the PoP key was generated in order for
|
|
14104
|
+
* PopTokenGenerator to query the full key for signing
|
|
14105
|
+
*/
|
|
14106
|
+
if (!request.keyId) {
|
|
14107
|
+
throw createClientAuthError(keyIdMissing);
|
|
14239
14108
|
}
|
|
14240
|
-
|
|
14109
|
+
return popTokenGenerator.signPopToken(response.access_token, request.keyId, shrParameters);
|
|
14241
14110
|
}
|
|
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
|
-
}
|
|
14111
|
+
else {
|
|
14112
|
+
return response.access_token;
|
|
14252
14113
|
}
|
|
14253
14114
|
}
|
|
14254
14115
|
/**
|
|
14255
|
-
*
|
|
14116
|
+
* Generates authentication result
|
|
14117
|
+
* @param response
|
|
14118
|
+
* @param request
|
|
14119
|
+
* @param idTokenObj
|
|
14120
|
+
* @param accountEntity
|
|
14121
|
+
* @param authority
|
|
14122
|
+
* @param reqTimestamp
|
|
14256
14123
|
* @returns
|
|
14257
14124
|
*/
|
|
14258
|
-
|
|
14259
|
-
|
|
14125
|
+
async generateAuthenticationResult(response, request, idTokenClaims, accountEntity, authority, reqTimestamp) {
|
|
14126
|
+
// Add Native Broker fields to Telemetry
|
|
14127
|
+
const mats = this.addTelemetryFromNativeResponse(response);
|
|
14128
|
+
// If scopes not returned in server response, use request scopes
|
|
14129
|
+
const responseScopes = response.scope
|
|
14130
|
+
? ScopeSet.fromString(response.scope)
|
|
14131
|
+
: ScopeSet.fromString(request.scope);
|
|
14132
|
+
const accountProperties = response.account.properties || {};
|
|
14133
|
+
const uid = accountProperties["UID"] ||
|
|
14134
|
+
idTokenClaims.oid ||
|
|
14135
|
+
idTokenClaims.sub ||
|
|
14136
|
+
Constants.EMPTY_STRING;
|
|
14137
|
+
const tid = accountProperties["TenantId"] ||
|
|
14138
|
+
idTokenClaims.tid ||
|
|
14139
|
+
Constants.EMPTY_STRING;
|
|
14140
|
+
const accountInfo = updateAccountTenantProfileData(accountEntity.getAccountInfo(), undefined, // tenantProfile optional
|
|
14141
|
+
idTokenClaims, response.id_token);
|
|
14142
|
+
/**
|
|
14143
|
+
* In pairwise broker flows, this check prevents the broker's native account id
|
|
14144
|
+
* from being returned over the embedded app's account id.
|
|
14145
|
+
*/
|
|
14146
|
+
if (accountInfo.nativeAccountId !== response.account.id) {
|
|
14147
|
+
accountInfo.nativeAccountId = response.account.id;
|
|
14148
|
+
}
|
|
14149
|
+
// generate PoP token as needed
|
|
14150
|
+
const responseAccessToken = await this.generatePopAccessToken(response, request);
|
|
14151
|
+
const tokenType = request.tokenType === AuthenticationScheme.POP
|
|
14152
|
+
? AuthenticationScheme.POP
|
|
14153
|
+
: AuthenticationScheme.BEARER;
|
|
14154
|
+
const result = {
|
|
14155
|
+
authority: authority,
|
|
14156
|
+
uniqueId: uid,
|
|
14157
|
+
tenantId: tid,
|
|
14158
|
+
scopes: responseScopes.asArray(),
|
|
14159
|
+
account: accountInfo,
|
|
14160
|
+
idToken: response.id_token,
|
|
14161
|
+
idTokenClaims: idTokenClaims,
|
|
14162
|
+
accessToken: responseAccessToken,
|
|
14163
|
+
fromCache: mats ? this.isResponseFromCache(mats) : false,
|
|
14164
|
+
// Request timestamp and NativeResponse expires_in are in seconds, converting to Date for AuthenticationResult
|
|
14165
|
+
expiresOn: toDateFromSeconds(reqTimestamp + response.expires_in),
|
|
14166
|
+
tokenType: tokenType,
|
|
14167
|
+
correlationId: this.correlationId,
|
|
14168
|
+
state: response.state,
|
|
14169
|
+
fromNativeBroker: true,
|
|
14170
|
+
};
|
|
14171
|
+
return result;
|
|
14260
14172
|
}
|
|
14261
14173
|
/**
|
|
14262
|
-
*
|
|
14263
|
-
* @
|
|
14174
|
+
* cache the account entity in browser storage
|
|
14175
|
+
* @param accountEntity
|
|
14264
14176
|
*/
|
|
14265
|
-
|
|
14266
|
-
|
|
14177
|
+
async cacheAccount(accountEntity) {
|
|
14178
|
+
// Store the account info and hence `nativeAccountId` in browser cache
|
|
14179
|
+
await this.browserStorage.setAccount(accountEntity, this.correlationId);
|
|
14180
|
+
// Remove any existing cached tokens for this account in browser storage
|
|
14181
|
+
this.browserStorage.removeAccountContext(accountEntity).catch((e) => {
|
|
14182
|
+
this.logger.error(`Error occurred while removing account context from browser storage. ${e}`);
|
|
14183
|
+
});
|
|
14267
14184
|
}
|
|
14268
14185
|
/**
|
|
14269
|
-
*
|
|
14270
|
-
* @param
|
|
14271
|
-
* @param
|
|
14272
|
-
* @param
|
|
14273
|
-
* @param
|
|
14186
|
+
* Stores the access_token and id_token in inmemory storage
|
|
14187
|
+
* @param response
|
|
14188
|
+
* @param request
|
|
14189
|
+
* @param homeAccountIdentifier
|
|
14190
|
+
* @param idTokenObj
|
|
14191
|
+
* @param responseAccessToken
|
|
14192
|
+
* @param tenantId
|
|
14193
|
+
* @param reqTimestamp
|
|
14274
14194
|
*/
|
|
14275
|
-
|
|
14276
|
-
|
|
14277
|
-
|
|
14278
|
-
|
|
14279
|
-
|
|
14280
|
-
|
|
14195
|
+
cacheNativeTokens(response, request, homeAccountIdentifier, idTokenClaims, responseAccessToken, tenantId, reqTimestamp) {
|
|
14196
|
+
const cachedIdToken = createIdTokenEntity(homeAccountIdentifier, request.authority, response.id_token || "", request.clientId, idTokenClaims.tid || "");
|
|
14197
|
+
// cache accessToken in inmemory storage
|
|
14198
|
+
const expiresIn = request.tokenType === AuthenticationScheme.POP
|
|
14199
|
+
? Constants.SHR_NONCE_VALIDITY
|
|
14200
|
+
: (typeof response.expires_in === "string"
|
|
14201
|
+
? parseInt(response.expires_in, 10)
|
|
14202
|
+
: response.expires_in) || 0;
|
|
14203
|
+
const tokenExpirationSeconds = reqTimestamp + expiresIn;
|
|
14204
|
+
const responseScopes = this.generateScopes(response, request);
|
|
14205
|
+
const cachedAccessToken = createAccessTokenEntity(homeAccountIdentifier, request.authority, responseAccessToken, request.clientId, idTokenClaims.tid || tenantId, responseScopes.printScopes(), tokenExpirationSeconds, 0, base64Decode, undefined, request.tokenType, undefined, request.keyId);
|
|
14206
|
+
const nativeCacheRecord = {
|
|
14207
|
+
idToken: cachedIdToken,
|
|
14208
|
+
accessToken: cachedAccessToken,
|
|
14209
|
+
};
|
|
14210
|
+
return this.nativeStorageManager.saveCacheRecord(nativeCacheRecord, this.correlationId, request.storeInCache);
|
|
14211
|
+
}
|
|
14212
|
+
addTelemetryFromNativeResponse(response) {
|
|
14213
|
+
const mats = this.getMATSFromResponse(response);
|
|
14214
|
+
if (!mats) {
|
|
14215
|
+
return null;
|
|
14281
14216
|
}
|
|
14282
|
-
|
|
14283
|
-
|
|
14284
|
-
|
|
14285
|
-
|
|
14217
|
+
this.performanceClient.addFields({
|
|
14218
|
+
extensionId: this.nativeMessageHandler.getExtensionId(),
|
|
14219
|
+
extensionVersion: this.nativeMessageHandler.getExtensionVersion(),
|
|
14220
|
+
matsBrokerVersion: mats.broker_version,
|
|
14221
|
+
matsAccountJoinOnStart: mats.account_join_on_start,
|
|
14222
|
+
matsAccountJoinOnEnd: mats.account_join_on_end,
|
|
14223
|
+
matsDeviceJoin: mats.device_join,
|
|
14224
|
+
matsPromptBehavior: mats.prompt_behavior,
|
|
14225
|
+
matsApiErrorCode: mats.api_error_code,
|
|
14226
|
+
matsUiVisible: mats.ui_visible,
|
|
14227
|
+
matsSilentCode: mats.silent_code,
|
|
14228
|
+
matsSilentBiSubCode: mats.silent_bi_sub_code,
|
|
14229
|
+
matsSilentMessage: mats.silent_message,
|
|
14230
|
+
matsSilentStatus: mats.silent_status,
|
|
14231
|
+
matsHttpStatus: mats.http_status,
|
|
14232
|
+
matsHttpEventCount: mats.http_event_count,
|
|
14233
|
+
}, this.correlationId);
|
|
14234
|
+
return mats;
|
|
14235
|
+
}
|
|
14236
|
+
/**
|
|
14237
|
+
* Validates native platform response before processing
|
|
14238
|
+
* @param response
|
|
14239
|
+
*/
|
|
14240
|
+
validateNativeResponse(response) {
|
|
14241
|
+
if (response.hasOwnProperty("access_token") &&
|
|
14242
|
+
response.hasOwnProperty("id_token") &&
|
|
14243
|
+
response.hasOwnProperty("client_info") &&
|
|
14244
|
+
response.hasOwnProperty("account") &&
|
|
14245
|
+
response.hasOwnProperty("scope") &&
|
|
14246
|
+
response.hasOwnProperty("expires_in")) {
|
|
14247
|
+
return response;
|
|
14286
14248
|
}
|
|
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
|
-
}
|
|
14249
|
+
else {
|
|
14250
|
+
throw createAuthError(unexpectedError, "Response missing expected properties.");
|
|
14297
14251
|
}
|
|
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
14252
|
}
|
|
14317
14253
|
/**
|
|
14318
|
-
*
|
|
14319
|
-
* @param
|
|
14254
|
+
* Gets MATS telemetry from native response
|
|
14255
|
+
* @param response
|
|
14256
|
+
* @returns
|
|
14320
14257
|
*/
|
|
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);
|
|
14258
|
+
getMATSFromResponse(response) {
|
|
14259
|
+
if (response.properties.MATS) {
|
|
14260
|
+
try {
|
|
14261
|
+
return JSON.parse(response.properties.MATS);
|
|
14332
14262
|
}
|
|
14333
|
-
|
|
14334
|
-
|
|
14263
|
+
catch (e) {
|
|
14264
|
+
this.logger.error("NativeInteractionClient - Error parsing MATS telemetry, returning null instead");
|
|
14335
14265
|
}
|
|
14336
14266
|
}
|
|
14337
|
-
return
|
|
14267
|
+
return null;
|
|
14338
14268
|
}
|
|
14339
14269
|
/**
|
|
14340
|
-
*
|
|
14341
|
-
* @param
|
|
14342
|
-
* @param state
|
|
14343
|
-
* @param authority
|
|
14344
|
-
* @param networkModule
|
|
14270
|
+
* Returns whether or not response came from native cache
|
|
14271
|
+
* @param response
|
|
14345
14272
|
* @returns
|
|
14346
14273
|
*/
|
|
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
|
-
}
|
|
14274
|
+
isResponseFromCache(mats) {
|
|
14275
|
+
if (typeof mats.is_cached === "undefined") {
|
|
14276
|
+
this.logger.verbose("NativeInteractionClient - MATS telemetry does not contain field indicating if response was served from cache. Returning false.");
|
|
14277
|
+
return false;
|
|
14371
14278
|
}
|
|
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;
|
|
14279
|
+
return !!mats.is_cached;
|
|
14375
14280
|
}
|
|
14376
14281
|
/**
|
|
14377
|
-
*
|
|
14282
|
+
* Translates developer provided request object into NativeRequest object
|
|
14283
|
+
* @param request
|
|
14378
14284
|
*/
|
|
14379
|
-
|
|
14285
|
+
async initializeNativeRequest(request) {
|
|
14286
|
+
this.logger.trace("NativeInteractionClient - initializeNativeRequest called");
|
|
14287
|
+
const requestAuthority = request.authority || this.config.auth.authority;
|
|
14380
14288
|
if (request.account) {
|
|
14381
|
-
|
|
14382
|
-
|
|
14383
|
-
|
|
14384
|
-
|
|
14289
|
+
// validate authority
|
|
14290
|
+
await this.getDiscoveredAuthority({
|
|
14291
|
+
requestAuthority,
|
|
14292
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
14293
|
+
account: request.account,
|
|
14294
|
+
});
|
|
14385
14295
|
}
|
|
14386
|
-
|
|
14387
|
-
|
|
14388
|
-
|
|
14389
|
-
|
|
14296
|
+
const canonicalAuthority = new UrlString(requestAuthority);
|
|
14297
|
+
canonicalAuthority.validateAsUri();
|
|
14298
|
+
// 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.
|
|
14299
|
+
const { scopes, ...remainingProperties } = request;
|
|
14300
|
+
const scopeSet = new ScopeSet(scopes || []);
|
|
14301
|
+
scopeSet.appendScopes(OIDC_DEFAULT_SCOPES);
|
|
14302
|
+
const getPrompt = () => {
|
|
14303
|
+
// If request is silent, prompt is always none
|
|
14304
|
+
switch (this.apiId) {
|
|
14305
|
+
case ApiId.ssoSilent:
|
|
14306
|
+
case ApiId.acquireTokenSilent_silentFlow:
|
|
14307
|
+
this.logger.trace("initializeNativeRequest: silent request sets prompt to none");
|
|
14308
|
+
return PromptValue.NONE;
|
|
14309
|
+
}
|
|
14310
|
+
// Prompt not provided, request may proceed and native broker decides if it needs to prompt
|
|
14311
|
+
if (!request.prompt) {
|
|
14312
|
+
this.logger.trace("initializeNativeRequest: prompt was not provided");
|
|
14313
|
+
return undefined;
|
|
14314
|
+
}
|
|
14315
|
+
// If request is interactive, check if prompt provided is allowed to go directly to native broker
|
|
14316
|
+
switch (request.prompt) {
|
|
14317
|
+
case PromptValue.NONE:
|
|
14318
|
+
case PromptValue.CONSENT:
|
|
14319
|
+
case PromptValue.LOGIN:
|
|
14320
|
+
this.logger.trace("initializeNativeRequest: prompt is compatible with native flow");
|
|
14321
|
+
return request.prompt;
|
|
14322
|
+
default:
|
|
14323
|
+
this.logger.trace(`initializeNativeRequest: prompt = ${request.prompt} is not compatible with native flow`);
|
|
14324
|
+
throw createBrowserAuthError(nativePromptNotSupported);
|
|
14325
|
+
}
|
|
14326
|
+
};
|
|
14327
|
+
const validatedRequest = {
|
|
14328
|
+
...remainingProperties,
|
|
14329
|
+
accountId: this.accountId,
|
|
14330
|
+
clientId: this.config.auth.clientId,
|
|
14331
|
+
authority: canonicalAuthority.urlString,
|
|
14332
|
+
scope: scopeSet.printScopes(),
|
|
14333
|
+
redirectUri: this.getRedirectUri(request.redirectUri),
|
|
14334
|
+
prompt: getPrompt(),
|
|
14335
|
+
correlationId: this.correlationId,
|
|
14336
|
+
tokenType: request.authenticationScheme,
|
|
14337
|
+
windowTitleSubstring: document.title,
|
|
14338
|
+
extraParameters: {
|
|
14339
|
+
...request.extraQueryParameters,
|
|
14340
|
+
...request.tokenQueryParameters,
|
|
14341
|
+
},
|
|
14342
|
+
extendedExpiryToken: false,
|
|
14343
|
+
keyId: request.popKid,
|
|
14344
|
+
};
|
|
14345
|
+
// Check for PoP token requests: signPopToken should only be set to true if popKid is not set
|
|
14346
|
+
if (validatedRequest.signPopToken && !!request.popKid) {
|
|
14347
|
+
throw createBrowserAuthError(invalidPopTokenRequest);
|
|
14348
|
+
}
|
|
14349
|
+
this.handleExtraBrokerParams(validatedRequest);
|
|
14350
|
+
validatedRequest.extraParameters =
|
|
14351
|
+
validatedRequest.extraParameters || {};
|
|
14352
|
+
validatedRequest.extraParameters.telemetry =
|
|
14353
|
+
NativeConstants.MATS_TELEMETRY;
|
|
14354
|
+
if (request.authenticationScheme === AuthenticationScheme.POP) {
|
|
14355
|
+
// add POP request type
|
|
14356
|
+
const shrParameters = {
|
|
14357
|
+
resourceRequestUri: request.resourceRequestUri,
|
|
14358
|
+
resourceRequestMethod: request.resourceRequestMethod,
|
|
14359
|
+
shrClaims: request.shrClaims,
|
|
14360
|
+
shrNonce: request.shrNonce,
|
|
14390
14361
|
};
|
|
14362
|
+
const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);
|
|
14363
|
+
// generate reqCnf if not provided in the request
|
|
14364
|
+
let reqCnfData;
|
|
14365
|
+
if (!validatedRequest.keyId) {
|
|
14366
|
+
const generatedReqCnfData = await invokeAsync(popTokenGenerator.generateCnf.bind(popTokenGenerator), PerformanceEvents.PopTokenGenerateCnf, this.logger, this.performanceClient, request.correlationId)(shrParameters, this.logger);
|
|
14367
|
+
reqCnfData = generatedReqCnfData.reqCnfString;
|
|
14368
|
+
validatedRequest.keyId = generatedReqCnfData.kid;
|
|
14369
|
+
validatedRequest.signPopToken = true;
|
|
14370
|
+
}
|
|
14371
|
+
else {
|
|
14372
|
+
reqCnfData = this.browserCrypto.base64UrlEncode(JSON.stringify({ kid: validatedRequest.keyId }));
|
|
14373
|
+
validatedRequest.signPopToken = false;
|
|
14374
|
+
}
|
|
14375
|
+
// SPAs require whole string to be passed to broker
|
|
14376
|
+
validatedRequest.reqCnf = reqCnfData;
|
|
14391
14377
|
}
|
|
14392
|
-
|
|
14378
|
+
this.addRequestSKUs(validatedRequest);
|
|
14379
|
+
return validatedRequest;
|
|
14393
14380
|
}
|
|
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);
|
|
14381
|
+
/**
|
|
14382
|
+
* Handles extra broker request parameters
|
|
14383
|
+
* @param request {NativeTokenRequest}
|
|
14384
|
+
* @private
|
|
14385
|
+
*/
|
|
14386
|
+
handleExtraBrokerParams(request) {
|
|
14387
|
+
const hasExtraBrokerParams = request.extraParameters &&
|
|
14388
|
+
request.extraParameters.hasOwnProperty(BROKER_CLIENT_ID) &&
|
|
14389
|
+
request.extraParameters.hasOwnProperty(BROKER_REDIRECT_URI) &&
|
|
14390
|
+
request.extraParameters.hasOwnProperty(CLIENT_ID);
|
|
14391
|
+
if (!request.embeddedClientId && !hasExtraBrokerParams) {
|
|
14392
|
+
return;
|
|
14408
14393
|
}
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
|
|
14394
|
+
let child_client_id = "";
|
|
14395
|
+
const child_redirect_uri = request.redirectUri;
|
|
14396
|
+
if (request.embeddedClientId) {
|
|
14397
|
+
request.redirectUri = this.config.auth.redirectUri;
|
|
14398
|
+
child_client_id = request.embeddedClientId;
|
|
14413
14399
|
}
|
|
14414
|
-
|
|
14415
|
-
|
|
14416
|
-
|
|
14417
|
-
|
|
14418
|
-
|
|
14419
|
-
|
|
14420
|
-
|
|
14421
|
-
|
|
14422
|
-
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
14426
|
-
|
|
14427
|
-
|
|
14428
|
-
if (platformStateObj.interactionType !== interactionType) {
|
|
14429
|
-
throw createBrowserAuthError(stateInteractionTypeMismatch);
|
|
14400
|
+
else if (request.extraParameters) {
|
|
14401
|
+
request.redirectUri =
|
|
14402
|
+
request.extraParameters[BROKER_REDIRECT_URI];
|
|
14403
|
+
child_client_id =
|
|
14404
|
+
request.extraParameters[CLIENT_ID];
|
|
14405
|
+
}
|
|
14406
|
+
request.extraParameters = {
|
|
14407
|
+
child_client_id,
|
|
14408
|
+
child_redirect_uri,
|
|
14409
|
+
};
|
|
14410
|
+
this.performanceClient?.addFields({
|
|
14411
|
+
embeddedClientId: child_client_id,
|
|
14412
|
+
embeddedRedirectUri: child_redirect_uri,
|
|
14413
|
+
}, request.correlationId);
|
|
14430
14414
|
}
|
|
14431
14415
|
}
|
|
14432
14416
|
|
|
@@ -14490,9 +14474,147 @@ async function getAuthCodeRequestUrl(config, authority, request, logger, perform
|
|
|
14490
14474
|
throw createClientConfigurationError(pkceParamsMissing);
|
|
14491
14475
|
}
|
|
14492
14476
|
const parameters = await invokeAsync(getStandardParameters, PerformanceEvents.GetStandardParams, logger, performanceClient, request.correlationId)(config, authority, request, logger, performanceClient);
|
|
14493
|
-
|
|
14477
|
+
addResponseType(parameters, OAuthResponseType.CODE);
|
|
14494
14478
|
addCodeChallengeParams(parameters, request.codeChallenge, Constants.S256_CODE_CHALLENGE_METHOD);
|
|
14479
|
+
addExtraQueryParameters(parameters, request.extraQueryParameters || {});
|
|
14495
14480
|
return getAuthorizeUrl(authority, parameters);
|
|
14481
|
+
}
|
|
14482
|
+
/**
|
|
14483
|
+
* Gets the form that will be posted to /authorize with request parameters when using EAR
|
|
14484
|
+
*/
|
|
14485
|
+
async function getEARForm(frame, config, authority, request, logger, performanceClient) {
|
|
14486
|
+
if (!request.earJwk) {
|
|
14487
|
+
throw createBrowserAuthError(earJwkEmpty);
|
|
14488
|
+
}
|
|
14489
|
+
const parameters = await getStandardParameters(config, authority, request, logger, performanceClient);
|
|
14490
|
+
addResponseType(parameters, OAuthResponseType.IDTOKEN_TOKEN_REFRESHTOKEN);
|
|
14491
|
+
addEARParameters(parameters, request.earJwk);
|
|
14492
|
+
const queryParams = new Map();
|
|
14493
|
+
addExtraQueryParameters(queryParams, request.extraQueryParameters || {});
|
|
14494
|
+
const url = getAuthorizeUrl(authority, queryParams);
|
|
14495
|
+
return createForm(frame, url, parameters);
|
|
14496
|
+
}
|
|
14497
|
+
/**
|
|
14498
|
+
* Creates form element in the provided document with auth parameters in the post body
|
|
14499
|
+
* @param frame
|
|
14500
|
+
* @param authorizeUrl
|
|
14501
|
+
* @param parameters
|
|
14502
|
+
* @returns
|
|
14503
|
+
*/
|
|
14504
|
+
function createForm(frame, authorizeUrl, parameters) {
|
|
14505
|
+
const form = frame.createElement("form");
|
|
14506
|
+
form.method = "post";
|
|
14507
|
+
form.action = authorizeUrl;
|
|
14508
|
+
parameters.forEach((value, key) => {
|
|
14509
|
+
const param = frame.createElement("input");
|
|
14510
|
+
param.hidden = true;
|
|
14511
|
+
param.name = key;
|
|
14512
|
+
param.value = value;
|
|
14513
|
+
form.appendChild(param);
|
|
14514
|
+
});
|
|
14515
|
+
frame.body.appendChild(form);
|
|
14516
|
+
return form;
|
|
14517
|
+
}
|
|
14518
|
+
/**
|
|
14519
|
+
* Response handler when server returns accountId on the /authorize request
|
|
14520
|
+
* @param request
|
|
14521
|
+
* @param accountId
|
|
14522
|
+
* @param apiId
|
|
14523
|
+
* @param config
|
|
14524
|
+
* @param browserStorage
|
|
14525
|
+
* @param nativeStorage
|
|
14526
|
+
* @param eventHandler
|
|
14527
|
+
* @param logger
|
|
14528
|
+
* @param performanceClient
|
|
14529
|
+
* @param nativeMessageHandler
|
|
14530
|
+
* @returns
|
|
14531
|
+
*/
|
|
14532
|
+
async function handleResponsePlatformBroker(request, accountId, apiId, config, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler) {
|
|
14533
|
+
if (!nativeMessageHandler) {
|
|
14534
|
+
throw createBrowserAuthError(nativeConnectionNotEstablished);
|
|
14535
|
+
}
|
|
14536
|
+
const browserCrypto = new CryptoOps(logger, performanceClient);
|
|
14537
|
+
const nativeInteractionClient = new NativeInteractionClient(config, browserStorage, browserCrypto, logger, eventHandler, config.system.navigationClient, apiId, performanceClient, nativeMessageHandler, accountId, nativeStorage, request.correlationId);
|
|
14538
|
+
const { userRequestState } = ProtocolUtils.parseRequestState(browserCrypto, request.state);
|
|
14539
|
+
return invokeAsync(nativeInteractionClient.acquireToken.bind(nativeInteractionClient), PerformanceEvents.NativeInteractionClientAcquireToken, logger, performanceClient, request.correlationId)({
|
|
14540
|
+
...request,
|
|
14541
|
+
state: userRequestState,
|
|
14542
|
+
prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
|
|
14543
|
+
});
|
|
14544
|
+
}
|
|
14545
|
+
/**
|
|
14546
|
+
* Response handler when server returns code on the /authorize request
|
|
14547
|
+
* @param request
|
|
14548
|
+
* @param response
|
|
14549
|
+
* @param codeVerifier
|
|
14550
|
+
* @param authClient
|
|
14551
|
+
* @param browserStorage
|
|
14552
|
+
* @param logger
|
|
14553
|
+
* @param performanceClient
|
|
14554
|
+
* @returns
|
|
14555
|
+
*/
|
|
14556
|
+
async function handleResponseCode(request, response, codeVerifier, apiId, config, authClient, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler) {
|
|
14557
|
+
// Remove throttle if it exists
|
|
14558
|
+
ThrottlingUtils.removeThrottle(browserStorage, config.auth.clientId, request);
|
|
14559
|
+
if (response.accountId) {
|
|
14560
|
+
return invokeAsync(handleResponsePlatformBroker, PerformanceEvents.HandleResponsePlatformBroker, logger, performanceClient, request.correlationId)(request, response.accountId, apiId, config, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler);
|
|
14561
|
+
}
|
|
14562
|
+
const authCodeRequest = {
|
|
14563
|
+
...request,
|
|
14564
|
+
code: response.code || "",
|
|
14565
|
+
codeVerifier: codeVerifier,
|
|
14566
|
+
};
|
|
14567
|
+
// Create popup interaction handler.
|
|
14568
|
+
const interactionHandler = new InteractionHandler(authClient, browserStorage, authCodeRequest, logger, performanceClient);
|
|
14569
|
+
// Handle response from hash string.
|
|
14570
|
+
const result = await invokeAsync(interactionHandler.handleCodeResponse.bind(interactionHandler), PerformanceEvents.HandleCodeResponse, logger, performanceClient, request.correlationId)(response, request);
|
|
14571
|
+
return result;
|
|
14572
|
+
}
|
|
14573
|
+
/**
|
|
14574
|
+
* Response handler when server returns ear_jwe on the /authorize request
|
|
14575
|
+
* @param request
|
|
14576
|
+
* @param response
|
|
14577
|
+
* @param apiId
|
|
14578
|
+
* @param config
|
|
14579
|
+
* @param authority
|
|
14580
|
+
* @param browserStorage
|
|
14581
|
+
* @param nativeStorage
|
|
14582
|
+
* @param eventHandler
|
|
14583
|
+
* @param logger
|
|
14584
|
+
* @param performanceClient
|
|
14585
|
+
* @param nativeMessageHandler
|
|
14586
|
+
* @returns
|
|
14587
|
+
*/
|
|
14588
|
+
async function handleResponseEAR(request, response, apiId, config, authority, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler) {
|
|
14589
|
+
// Remove throttle if it exists
|
|
14590
|
+
ThrottlingUtils.removeThrottle(browserStorage, config.auth.clientId, request);
|
|
14591
|
+
// Validate state & check response for errors
|
|
14592
|
+
validateAuthorizationResponse(response, request.state);
|
|
14593
|
+
if (!response.ear_jwe) {
|
|
14594
|
+
throw createBrowserAuthError(earJweEmpty);
|
|
14595
|
+
}
|
|
14596
|
+
if (!request.earJwk) {
|
|
14597
|
+
throw createBrowserAuthError(earJwkEmpty);
|
|
14598
|
+
}
|
|
14599
|
+
const decryptedData = JSON.parse(await invokeAsync(decryptEarResponse, PerformanceEvents.DecryptEarResponse, logger, performanceClient, request.correlationId)(request.earJwk, response.ear_jwe));
|
|
14600
|
+
if (decryptedData.accountId) {
|
|
14601
|
+
return invokeAsync(handleResponsePlatformBroker, PerformanceEvents.HandleResponsePlatformBroker, logger, performanceClient, request.correlationId)(request, decryptedData.accountId, apiId, config, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler);
|
|
14602
|
+
}
|
|
14603
|
+
const responseHandler = new ResponseHandler(config.auth.clientId, browserStorage, new CryptoOps(logger, performanceClient), logger, null, null, performanceClient);
|
|
14604
|
+
// Validate response. This function throws a server error if an error is returned by the server.
|
|
14605
|
+
responseHandler.validateTokenResponse(decryptedData);
|
|
14606
|
+
// Temporary until response handler is refactored to be more flow agnostic.
|
|
14607
|
+
const additionalData = {
|
|
14608
|
+
code: "",
|
|
14609
|
+
state: request.state,
|
|
14610
|
+
nonce: request.nonce,
|
|
14611
|
+
client_info: decryptedData.client_info,
|
|
14612
|
+
cloud_graph_host_name: decryptedData.cloud_graph_host_name,
|
|
14613
|
+
cloud_instance_host_name: decryptedData.cloud_instance_host_name,
|
|
14614
|
+
cloud_instance_name: decryptedData.cloud_instance_name,
|
|
14615
|
+
msgraph_host: decryptedData.msgraph_host,
|
|
14616
|
+
};
|
|
14617
|
+
return (await invokeAsync(responseHandler.handleServerTokenResponse.bind(responseHandler), PerformanceEvents.HandleServerTokenResponse, logger, performanceClient, request.correlationId)(decryptedData, authority, nowSeconds(), request, additionalData, undefined, undefined, undefined, undefined));
|
|
14496
14618
|
}
|
|
14497
14619
|
|
|
14498
14620
|
/*
|
|
@@ -14560,6 +14682,7 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14560
14682
|
// Properly sets this reference for the unload event.
|
|
14561
14683
|
this.unloadWindow = this.unloadWindow.bind(this);
|
|
14562
14684
|
this.nativeStorage = nativeStorageImpl;
|
|
14685
|
+
this.eventHandler = eventHandler;
|
|
14563
14686
|
}
|
|
14564
14687
|
/**
|
|
14565
14688
|
* Acquires tokens by opening a popup window to the /authorize endpoint of the authority
|
|
@@ -14635,11 +14758,7 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14635
14758
|
*/
|
|
14636
14759
|
async acquireTokenPopupAsync(request, popupParams, pkceCodes) {
|
|
14637
14760
|
this.logger.verbose("acquireTokenPopupAsync called");
|
|
14638
|
-
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenPopup);
|
|
14639
14761
|
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
14762
|
/*
|
|
14644
14763
|
* Skip pre-connect for async popups to reduce time between user interaction and popup window creation to avoid
|
|
14645
14764
|
* popup from being blocked by browsers with shorter popup timers
|
|
@@ -14647,65 +14766,49 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14647
14766
|
if (popupParams.popup) {
|
|
14648
14767
|
preconnect(validRequest.authority);
|
|
14649
14768
|
}
|
|
14769
|
+
const isPlatformBroker = NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
|
|
14770
|
+
validRequest.platformBroker = isPlatformBroker;
|
|
14771
|
+
if (this.config.auth.protocolMode === ProtocolMode.EAR) {
|
|
14772
|
+
return this.executeEarFlow(validRequest, popupParams);
|
|
14773
|
+
}
|
|
14774
|
+
else {
|
|
14775
|
+
return this.executeCodeFlow(validRequest, popupParams, pkceCodes);
|
|
14776
|
+
}
|
|
14777
|
+
}
|
|
14778
|
+
/**
|
|
14779
|
+
* Executes auth code + PKCE flow
|
|
14780
|
+
* @param request
|
|
14781
|
+
* @param popupParams
|
|
14782
|
+
* @param pkceCodes
|
|
14783
|
+
* @returns
|
|
14784
|
+
*/
|
|
14785
|
+
async executeCodeFlow(request, popupParams, pkceCodes) {
|
|
14786
|
+
const correlationId = request.correlationId;
|
|
14787
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenPopup);
|
|
14788
|
+
const pkce = pkceCodes ||
|
|
14789
|
+
(await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, correlationId)(this.performanceClient, this.logger, correlationId));
|
|
14790
|
+
const popupRequest = {
|
|
14791
|
+
...request,
|
|
14792
|
+
codeChallenge: pkce.challenge,
|
|
14793
|
+
};
|
|
14650
14794
|
try {
|
|
14651
14795
|
// Initialize the client
|
|
14652
|
-
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient,
|
|
14796
|
+
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, correlationId)({
|
|
14653
14797
|
serverTelemetryManager,
|
|
14654
|
-
requestAuthority:
|
|
14655
|
-
requestAzureCloudOptions:
|
|
14656
|
-
requestExtraQueryParameters:
|
|
14657
|
-
account:
|
|
14798
|
+
requestAuthority: popupRequest.authority,
|
|
14799
|
+
requestAzureCloudOptions: popupRequest.azureCloudOptions,
|
|
14800
|
+
requestExtraQueryParameters: popupRequest.extraQueryParameters,
|
|
14801
|
+
account: popupRequest.account,
|
|
14658
14802
|
});
|
|
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
14803
|
// 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);
|
|
14804
|
+
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, correlationId)(this.config, authClient.authority, popupRequest, this.logger, this.performanceClient);
|
|
14671
14805
|
// Show the UI once the url has been created. Get the window handle for the popup.
|
|
14672
14806
|
const popupWindow = this.initiateAuthRequest(navigateUrl, popupParams);
|
|
14673
14807
|
this.eventHandler.emitEvent(EventType.POPUP_OPENED, exports.InteractionType.Popup, { popupWindow }, null);
|
|
14674
14808
|
// 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
14809
|
const responseString = await this.monitorPopupForHash(popupWindow, popupParams.popupWindowParent);
|
|
14676
14810
|
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;
|
|
14811
|
+
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
14812
|
}
|
|
14710
14813
|
catch (e) {
|
|
14711
14814
|
// Close the synchronous popup if an error is thrown before the window unload event is registered
|
|
@@ -14717,6 +14820,32 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14717
14820
|
throw e;
|
|
14718
14821
|
}
|
|
14719
14822
|
}
|
|
14823
|
+
/**
|
|
14824
|
+
* Executes EAR flow
|
|
14825
|
+
* @param request
|
|
14826
|
+
*/
|
|
14827
|
+
async executeEarFlow(request, popupParams) {
|
|
14828
|
+
const correlationId = request.correlationId;
|
|
14829
|
+
// Get the frame handle for the silent request
|
|
14830
|
+
const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, correlationId)({
|
|
14831
|
+
requestAuthority: request.authority,
|
|
14832
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
14833
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
14834
|
+
account: request.account,
|
|
14835
|
+
});
|
|
14836
|
+
const earJwk = await invokeAsync(generateEarKey, PerformanceEvents.GenerateEarKey, this.logger, this.performanceClient, correlationId)();
|
|
14837
|
+
const popupRequest = {
|
|
14838
|
+
...request,
|
|
14839
|
+
earJwk: earJwk,
|
|
14840
|
+
};
|
|
14841
|
+
const popupWindow = popupParams.popup || this.openPopup("about:blank", popupParams);
|
|
14842
|
+
const form = await getEARForm(popupWindow.document, this.config, discoveredAuthority, popupRequest, this.logger, this.performanceClient);
|
|
14843
|
+
form.submit();
|
|
14844
|
+
// Monitor the popup for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
|
|
14845
|
+
const responseString = await invokeAsync(this.monitorPopupForHash.bind(this), PerformanceEvents.SilentHandlerMonitorIframeForHash, this.logger, this.performanceClient, correlationId)(popupWindow, popupParams.popupWindowParent);
|
|
14846
|
+
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, this.correlationId)(responseString, this.config.auth.OIDCOptions.serverResponseType, this.logger);
|
|
14847
|
+
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);
|
|
14848
|
+
}
|
|
14720
14849
|
/**
|
|
14721
14850
|
*
|
|
14722
14851
|
* @param validRequest
|
|
@@ -14792,7 +14921,6 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14792
14921
|
e.setCorrelationId(this.correlationId);
|
|
14793
14922
|
serverTelemetryManager.cacheFailedRequest(e);
|
|
14794
14923
|
}
|
|
14795
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
14796
14924
|
this.eventHandler.emitEvent(EventType.LOGOUT_FAILURE, exports.InteractionType.Popup, null, e);
|
|
14797
14925
|
this.eventHandler.emitEvent(EventType.LOGOUT_END, exports.InteractionType.Popup);
|
|
14798
14926
|
throw e;
|
|
@@ -14904,7 +15032,6 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14904
15032
|
}
|
|
14905
15033
|
catch (e) {
|
|
14906
15034
|
this.logger.error("error opening popup " + e.message);
|
|
14907
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
14908
15035
|
throw createBrowserAuthError(popupWindowError);
|
|
14909
15036
|
}
|
|
14910
15037
|
}
|
|
@@ -14962,7 +15089,6 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14962
15089
|
* Event callback to unload main window.
|
|
14963
15090
|
*/
|
|
14964
15091
|
unloadWindow(e) {
|
|
14965
|
-
this.browserStorage.cleanRequestByInteractionType(exports.InteractionType.Popup);
|
|
14966
15092
|
if (this.currentWindow) {
|
|
14967
15093
|
this.currentWindow.close();
|
|
14968
15094
|
}
|
|
@@ -14978,8 +15104,6 @@ class PopupClient extends StandardInteractionClient {
|
|
|
14978
15104
|
popupWindow.close();
|
|
14979
15105
|
// Remove window unload function
|
|
14980
15106
|
popupWindowParent.removeEventListener("beforeunload", this.unloadWindow);
|
|
14981
|
-
// Interaction is completed - remove interaction status.
|
|
14982
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
14983
15107
|
}
|
|
14984
15108
|
/**
|
|
14985
15109
|
* Generates the name for the popup based on the client id and request
|
|
@@ -15000,141 +15124,6 @@ class PopupClient extends StandardInteractionClient {
|
|
|
15000
15124
|
}
|
|
15001
15125
|
}
|
|
15002
15126
|
|
|
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
15127
|
/*
|
|
15139
15128
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
15140
15129
|
* Licensed under the MIT License.
|
|
@@ -15162,62 +15151,96 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15162
15151
|
*/
|
|
15163
15152
|
async acquireToken(request) {
|
|
15164
15153
|
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);
|
|
15154
|
+
validRequest.platformBroker =
|
|
15155
|
+
NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
|
|
15169
15156
|
const handleBackButton = (event) => {
|
|
15170
15157
|
// Clear temporary cache if the back button is clicked during the redirect flow.
|
|
15171
15158
|
if (event.persisted) {
|
|
15172
15159
|
this.logger.verbose("Page was restored from back/forward cache. Clearing temporary cache.");
|
|
15173
|
-
this.browserStorage.
|
|
15160
|
+
this.browserStorage.resetRequestCache();
|
|
15174
15161
|
this.eventHandler.emitEvent(EventType.RESTORE_FROM_BFCACHE, exports.InteractionType.Redirect);
|
|
15175
15162
|
}
|
|
15176
15163
|
};
|
|
15164
|
+
const redirectStartPage = this.getRedirectStartPage(request.redirectStartPage);
|
|
15165
|
+
this.logger.verbosePii(`Redirect start page: ${redirectStartPage}`);
|
|
15166
|
+
// Cache start page, returns to this page after redirectUri if navigateToLoginRequestUrl is true
|
|
15167
|
+
this.browserStorage.setTemporaryCache(TemporaryCacheKeys.ORIGIN_URI, redirectStartPage, true);
|
|
15168
|
+
// Clear temporary cache if the back button is clicked during the redirect flow.
|
|
15169
|
+
window.addEventListener("pageshow", handleBackButton);
|
|
15170
|
+
try {
|
|
15171
|
+
if (this.config.auth.protocolMode === ProtocolMode.EAR) {
|
|
15172
|
+
await this.executeEarFlow(validRequest);
|
|
15173
|
+
}
|
|
15174
|
+
else {
|
|
15175
|
+
await this.executeCodeFlow(validRequest, request.onRedirectNavigate);
|
|
15176
|
+
}
|
|
15177
|
+
}
|
|
15178
|
+
catch (e) {
|
|
15179
|
+
if (e instanceof AuthError) {
|
|
15180
|
+
e.setCorrelationId(this.correlationId);
|
|
15181
|
+
}
|
|
15182
|
+
window.removeEventListener("pageshow", handleBackButton);
|
|
15183
|
+
throw e;
|
|
15184
|
+
}
|
|
15185
|
+
}
|
|
15186
|
+
/**
|
|
15187
|
+
* Executes auth code + PKCE flow
|
|
15188
|
+
* @param request
|
|
15189
|
+
* @returns
|
|
15190
|
+
*/
|
|
15191
|
+
async executeCodeFlow(request, onRedirectNavigate) {
|
|
15192
|
+
const correlationId = request.correlationId;
|
|
15193
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenRedirect);
|
|
15194
|
+
const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, correlationId)(this.performanceClient, this.logger, correlationId);
|
|
15195
|
+
const redirectRequest = {
|
|
15196
|
+
...request,
|
|
15197
|
+
codeChallenge: pkceCodes.challenge,
|
|
15198
|
+
};
|
|
15199
|
+
this.browserStorage.cacheAuthorizeRequest(redirectRequest, pkceCodes.verifier);
|
|
15177
15200
|
try {
|
|
15178
15201
|
// Initialize the client
|
|
15179
15202
|
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)({
|
|
15180
15203
|
serverTelemetryManager,
|
|
15181
|
-
requestAuthority:
|
|
15182
|
-
requestAzureCloudOptions:
|
|
15183
|
-
requestExtraQueryParameters:
|
|
15184
|
-
account:
|
|
15204
|
+
requestAuthority: redirectRequest.authority,
|
|
15205
|
+
requestAzureCloudOptions: redirectRequest.azureCloudOptions,
|
|
15206
|
+
requestExtraQueryParameters: redirectRequest.extraQueryParameters,
|
|
15207
|
+
account: redirectRequest.account,
|
|
15185
15208
|
});
|
|
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
15209
|
// 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);
|
|
15210
|
+
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, request.correlationId)(this.config, authClient.authority, redirectRequest, this.logger, this.performanceClient);
|
|
15202
15211
|
// 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
|
-
});
|
|
15212
|
+
return await this.initiateAuthRequest(navigateUrl, onRedirectNavigate);
|
|
15210
15213
|
}
|
|
15211
15214
|
catch (e) {
|
|
15212
15215
|
if (e instanceof AuthError) {
|
|
15213
15216
|
e.setCorrelationId(this.correlationId);
|
|
15214
15217
|
serverTelemetryManager.cacheFailedRequest(e);
|
|
15215
15218
|
}
|
|
15216
|
-
window.removeEventListener("pageshow", handleBackButton);
|
|
15217
|
-
this.browserStorage.cleanRequestByState(validRequest.state);
|
|
15218
15219
|
throw e;
|
|
15219
15220
|
}
|
|
15220
15221
|
}
|
|
15222
|
+
/**
|
|
15223
|
+
* Executes EAR flow
|
|
15224
|
+
* @param request
|
|
15225
|
+
*/
|
|
15226
|
+
async executeEarFlow(request) {
|
|
15227
|
+
const correlationId = request.correlationId;
|
|
15228
|
+
// Get the frame handle for the silent request
|
|
15229
|
+
const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, correlationId)({
|
|
15230
|
+
requestAuthority: request.authority,
|
|
15231
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
15232
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
15233
|
+
account: request.account,
|
|
15234
|
+
});
|
|
15235
|
+
const earJwk = await invokeAsync(generateEarKey, PerformanceEvents.GenerateEarKey, this.logger, this.performanceClient, correlationId)();
|
|
15236
|
+
const redirectRequest = {
|
|
15237
|
+
...request,
|
|
15238
|
+
earJwk: earJwk,
|
|
15239
|
+
};
|
|
15240
|
+
this.browserStorage.cacheAuthorizeRequest(redirectRequest);
|
|
15241
|
+
const form = await getEARForm(document, this.config, discoveredAuthority, redirectRequest, this.logger, this.performanceClient);
|
|
15242
|
+
form.submit();
|
|
15243
|
+
}
|
|
15221
15244
|
/**
|
|
15222
15245
|
* Checks if navigateToLoginRequestUrl is set, and:
|
|
15223
15246
|
* - if true, performs logic to cache and navigate
|
|
@@ -15225,18 +15248,14 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15225
15248
|
* @param hash {string} url hash
|
|
15226
15249
|
* @param parentMeasurement {InProgressPerformanceEvent} parent measurement
|
|
15227
15250
|
*/
|
|
15228
|
-
async handleRedirectPromise(hash = "", parentMeasurement) {
|
|
15251
|
+
async handleRedirectPromise(hash = "", request, pkceVerifier, parentMeasurement) {
|
|
15229
15252
|
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.handleRedirectPromise);
|
|
15230
15253
|
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
15254
|
const [serverParams, responseString] = this.getRedirectResponse(hash || "");
|
|
15236
15255
|
if (!serverParams) {
|
|
15237
15256
|
// Not a recognized server response hash or hash not associated with a redirect request
|
|
15238
15257
|
this.logger.info("handleRedirectPromise did not detect a response as a result of a redirect. Cleaning temporary cache.");
|
|
15239
|
-
this.browserStorage.
|
|
15258
|
+
this.browserStorage.resetRequestCache();
|
|
15240
15259
|
// Do not instrument "no_server_response" if user clicked back button
|
|
15241
15260
|
if (getNavigationType() !== "back_forward") {
|
|
15242
15261
|
parentMeasurement.event.errorCode = "no_server_response";
|
|
@@ -15258,12 +15277,12 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15258
15277
|
// Replace current hash with non-msal hash, if present
|
|
15259
15278
|
replaceHash(loginRequestUrl);
|
|
15260
15279
|
}
|
|
15261
|
-
const handleHashResult = await this.handleResponse(serverParams, serverTelemetryManager);
|
|
15280
|
+
const handleHashResult = await this.handleResponse(serverParams, request, pkceVerifier, serverTelemetryManager);
|
|
15262
15281
|
return handleHashResult;
|
|
15263
15282
|
}
|
|
15264
15283
|
else if (!this.config.auth.navigateToLoginRequestUrl) {
|
|
15265
15284
|
this.logger.verbose("NavigateToLoginRequestUrl set to false, handling response");
|
|
15266
|
-
return await this.handleResponse(serverParams, serverTelemetryManager);
|
|
15285
|
+
return await this.handleResponse(serverParams, request, pkceVerifier, serverTelemetryManager);
|
|
15267
15286
|
}
|
|
15268
15287
|
else if (!isInIframe() ||
|
|
15269
15288
|
this.config.system.allowRedirectInIframe) {
|
|
@@ -15299,7 +15318,7 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15299
15318
|
}
|
|
15300
15319
|
// If navigateInternal implementation returns false, handle the hash now
|
|
15301
15320
|
if (!processHashOnRedirect) {
|
|
15302
|
-
return await this.handleResponse(serverParams, serverTelemetryManager);
|
|
15321
|
+
return await this.handleResponse(serverParams, request, pkceVerifier, serverTelemetryManager);
|
|
15303
15322
|
}
|
|
15304
15323
|
}
|
|
15305
15324
|
return null;
|
|
@@ -15309,7 +15328,6 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15309
15328
|
e.setCorrelationId(this.correlationId);
|
|
15310
15329
|
serverTelemetryManager.cacheFailedRequest(e);
|
|
15311
15330
|
}
|
|
15312
|
-
this.browserStorage.cleanRequestByInteractionType(exports.InteractionType.Redirect);
|
|
15313
15331
|
throw e;
|
|
15314
15332
|
}
|
|
15315
15333
|
}
|
|
@@ -15362,39 +15380,67 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15362
15380
|
* @param hash
|
|
15363
15381
|
* @param state
|
|
15364
15382
|
*/
|
|
15365
|
-
async handleResponse(serverParams, serverTelemetryManager) {
|
|
15383
|
+
async handleResponse(serverParams, request, codeVerifier, serverTelemetryManager) {
|
|
15366
15384
|
const state = serverParams.state;
|
|
15367
15385
|
if (!state) {
|
|
15368
15386
|
throw createBrowserAuthError(noStateInHash);
|
|
15369
15387
|
}
|
|
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);
|
|
15388
|
+
if (serverParams.ear_jwe) {
|
|
15389
|
+
const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, request.correlationId)({
|
|
15390
|
+
requestAuthority: request.authority,
|
|
15391
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
15392
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
15393
|
+
account: request.account,
|
|
15387
15394
|
});
|
|
15395
|
+
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);
|
|
15396
|
+
}
|
|
15397
|
+
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)({ serverTelemetryManager, requestAuthority: request.authority });
|
|
15398
|
+
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);
|
|
15399
|
+
}
|
|
15400
|
+
/**
|
|
15401
|
+
* Redirects window to given URL.
|
|
15402
|
+
* @param urlNavigate
|
|
15403
|
+
* @param onRedirectNavigateRequest - onRedirectNavigate callback provided on the request
|
|
15404
|
+
*/
|
|
15405
|
+
async initiateAuthRequest(requestUrl, onRedirectNavigateRequest) {
|
|
15406
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest called");
|
|
15407
|
+
// Navigate if valid URL
|
|
15408
|
+
if (requestUrl) {
|
|
15409
|
+
this.logger.infoPii(`RedirectHandler.initiateAuthRequest: Navigate to: ${requestUrl}`);
|
|
15410
|
+
const navigationOptions = {
|
|
15411
|
+
apiId: ApiId.acquireTokenRedirect,
|
|
15412
|
+
timeout: this.config.system.redirectNavigationTimeout,
|
|
15413
|
+
noHistory: false,
|
|
15414
|
+
};
|
|
15415
|
+
const onRedirectNavigate = onRedirectNavigateRequest ||
|
|
15416
|
+
this.config.auth.onRedirectNavigate;
|
|
15417
|
+
// If onRedirectNavigate is implemented, invoke it and provide requestUrl
|
|
15418
|
+
if (typeof onRedirectNavigate === "function") {
|
|
15419
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest: Invoking onRedirectNavigate callback");
|
|
15420
|
+
const navigate = onRedirectNavigate(requestUrl);
|
|
15421
|
+
// Returning false from onRedirectNavigate will stop navigation
|
|
15422
|
+
if (navigate !== false) {
|
|
15423
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate did not return false, navigating");
|
|
15424
|
+
await this.navigationClient.navigateExternal(requestUrl, navigationOptions);
|
|
15425
|
+
return;
|
|
15426
|
+
}
|
|
15427
|
+
else {
|
|
15428
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate returned false, stopping navigation");
|
|
15429
|
+
return;
|
|
15430
|
+
}
|
|
15431
|
+
}
|
|
15432
|
+
else {
|
|
15433
|
+
// Navigate window to request URL
|
|
15434
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest: Navigating window to navigate url");
|
|
15435
|
+
await this.navigationClient.navigateExternal(requestUrl, navigationOptions);
|
|
15436
|
+
return;
|
|
15437
|
+
}
|
|
15388
15438
|
}
|
|
15389
|
-
|
|
15390
|
-
|
|
15391
|
-
|
|
15392
|
-
throw createBrowserAuthError(
|
|
15439
|
+
else {
|
|
15440
|
+
// Throw error if request URL is empty.
|
|
15441
|
+
this.logger.info("RedirectHandler.initiateAuthRequest: Navigate url is empty");
|
|
15442
|
+
throw createBrowserAuthError(emptyNavigateUri);
|
|
15393
15443
|
}
|
|
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
15444
|
}
|
|
15399
15445
|
/**
|
|
15400
15446
|
* Use to log out the current user, and redirect the user to the postLogoutRedirectUri.
|
|
@@ -15493,7 +15539,7 @@ class RedirectClient extends StandardInteractionClient {
|
|
|
15493
15539
|
* @param urlNavigate
|
|
15494
15540
|
* @param userRequestScopes
|
|
15495
15541
|
*/
|
|
15496
|
-
async function
|
|
15542
|
+
async function initiateCodeRequest(requestUrl, performanceClient, logger, correlationId, navigateFrameWait) {
|
|
15497
15543
|
performanceClient.addQueueMeasurement(PerformanceEvents.SilentHandlerInitiateAuthRequest, correlationId);
|
|
15498
15544
|
if (!requestUrl) {
|
|
15499
15545
|
// Throw error if request URL is empty.
|
|
@@ -15505,6 +15551,15 @@ async function initiateAuthRequest(requestUrl, performanceClient, logger, correl
|
|
|
15505
15551
|
}
|
|
15506
15552
|
return invoke(loadFrameSync, PerformanceEvents.SilentHandlerLoadFrameSync, logger, performanceClient, correlationId)(requestUrl);
|
|
15507
15553
|
}
|
|
15554
|
+
async function initiateEarRequest(config, authority, request, logger, performanceClient) {
|
|
15555
|
+
const frame = createHiddenIframe();
|
|
15556
|
+
if (!frame.contentDocument) {
|
|
15557
|
+
throw "No document associated with iframe!";
|
|
15558
|
+
}
|
|
15559
|
+
const form = await getEARForm(frame.contentDocument, config, authority, request, logger, performanceClient);
|
|
15560
|
+
form.submit();
|
|
15561
|
+
return frame;
|
|
15562
|
+
}
|
|
15508
15563
|
/**
|
|
15509
15564
|
* Monitors an iframe content window until it loads a url with a known hash, or hits a specified timeout.
|
|
15510
15565
|
* @param iframe
|
|
@@ -15655,19 +15710,34 @@ class SilentIframeClient extends StandardInteractionClient {
|
|
|
15655
15710
|
}
|
|
15656
15711
|
// Create silent request
|
|
15657
15712
|
const silentRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, request.correlationId)(inputRequest, exports.InteractionType.Silent);
|
|
15713
|
+
silentRequest.platformBroker =
|
|
15714
|
+
NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, silentRequest.authenticationScheme);
|
|
15658
15715
|
preconnect(silentRequest.authority);
|
|
15659
|
-
|
|
15716
|
+
if (this.config.auth.protocolMode === ProtocolMode.EAR) {
|
|
15717
|
+
return this.executeEarFlow(silentRequest);
|
|
15718
|
+
}
|
|
15719
|
+
else {
|
|
15720
|
+
return this.executeCodeFlow(silentRequest);
|
|
15721
|
+
}
|
|
15722
|
+
}
|
|
15723
|
+
/**
|
|
15724
|
+
* Executes auth code + PKCE flow
|
|
15725
|
+
* @param request
|
|
15726
|
+
* @returns
|
|
15727
|
+
*/
|
|
15728
|
+
async executeCodeFlow(request) {
|
|
15660
15729
|
let authClient;
|
|
15730
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
15661
15731
|
try {
|
|
15662
15732
|
// Initialize the client
|
|
15663
15733
|
authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, request.correlationId)({
|
|
15664
15734
|
serverTelemetryManager,
|
|
15665
|
-
requestAuthority:
|
|
15666
|
-
requestAzureCloudOptions:
|
|
15667
|
-
requestExtraQueryParameters:
|
|
15668
|
-
account:
|
|
15735
|
+
requestAuthority: request.authority,
|
|
15736
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
15737
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
15738
|
+
account: request.account,
|
|
15669
15739
|
});
|
|
15670
|
-
return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, request.correlationId)(authClient,
|
|
15740
|
+
return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, request.correlationId)(authClient, request);
|
|
15671
15741
|
}
|
|
15672
15742
|
catch (e) {
|
|
15673
15743
|
if (e instanceof AuthError) {
|
|
@@ -15682,10 +15752,33 @@ class SilentIframeClient extends StandardInteractionClient {
|
|
|
15682
15752
|
this.performanceClient.addFields({
|
|
15683
15753
|
retryError: e.errorCode,
|
|
15684
15754
|
}, this.correlationId);
|
|
15685
|
-
|
|
15686
|
-
return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, this.correlationId)(authClient, retrySilentRequest);
|
|
15755
|
+
return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, this.correlationId)(authClient, request);
|
|
15687
15756
|
}
|
|
15688
15757
|
}
|
|
15758
|
+
/**
|
|
15759
|
+
* Executes EAR flow
|
|
15760
|
+
* @param request
|
|
15761
|
+
*/
|
|
15762
|
+
async executeEarFlow(request) {
|
|
15763
|
+
const correlationId = request.correlationId;
|
|
15764
|
+
const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, correlationId)({
|
|
15765
|
+
requestAuthority: request.authority,
|
|
15766
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
15767
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
15768
|
+
account: request.account,
|
|
15769
|
+
});
|
|
15770
|
+
const earJwk = await invokeAsync(generateEarKey, PerformanceEvents.GenerateEarKey, this.logger, this.performanceClient, correlationId)();
|
|
15771
|
+
const silentRequest = {
|
|
15772
|
+
...request,
|
|
15773
|
+
earJwk: earJwk,
|
|
15774
|
+
};
|
|
15775
|
+
const msalFrame = await invokeAsync(initiateEarRequest, PerformanceEvents.SilentHandlerInitiateAuthRequest, this.logger, this.performanceClient, correlationId)(this.config, discoveredAuthority, silentRequest, this.logger, this.performanceClient);
|
|
15776
|
+
const responseType = this.config.auth.OIDCOptions.serverResponseType;
|
|
15777
|
+
// Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
|
|
15778
|
+
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);
|
|
15779
|
+
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, correlationId)(responseString, responseType, this.logger);
|
|
15780
|
+
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);
|
|
15781
|
+
}
|
|
15689
15782
|
/**
|
|
15690
15783
|
* Currently Unsupported
|
|
15691
15784
|
*/
|
|
@@ -15702,44 +15795,20 @@ class SilentIframeClient extends StandardInteractionClient {
|
|
|
15702
15795
|
async silentTokenHelper(authClient, request) {
|
|
15703
15796
|
const correlationId = request.correlationId;
|
|
15704
15797
|
this.performanceClient.addQueueMeasurement(PerformanceEvents.SilentIframeClientTokenHelper, correlationId);
|
|
15705
|
-
const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient,
|
|
15798
|
+
const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, correlationId)(this.performanceClient, this.logger, correlationId);
|
|
15706
15799
|
const silentRequest = {
|
|
15707
15800
|
...request,
|
|
15708
15801
|
codeChallenge: pkceCodes.challenge,
|
|
15709
15802
|
};
|
|
15710
15803
|
// 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);
|
|
15804
|
+
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, correlationId)(this.config, authClient.authority, silentRequest, this.logger, this.performanceClient);
|
|
15715
15805
|
// Get the frame handle for the silent request
|
|
15716
|
-
const msalFrame = await invokeAsync(
|
|
15806
|
+
const msalFrame = await invokeAsync(initiateCodeRequest, PerformanceEvents.SilentHandlerInitiateAuthRequest, this.logger, this.performanceClient, correlationId)(navigateUrl, this.performanceClient, this.logger, correlationId, this.config.system.navigateFrameWait);
|
|
15717
15807
|
const responseType = this.config.auth.OIDCOptions.serverResponseType;
|
|
15718
15808
|
// 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
15809
|
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);
|
|
15810
|
+
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, correlationId)(responseString, responseType, this.logger);
|
|
15811
|
+
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
15812
|
}
|
|
15744
15813
|
}
|
|
15745
15814
|
|
|
@@ -16268,31 +16337,38 @@ class StandardController {
|
|
|
16268
16337
|
* @returns
|
|
16269
16338
|
*/
|
|
16270
16339
|
async handleRedirectPromiseInternal(hash) {
|
|
16340
|
+
if (!this.browserStorage.isInteractionInProgress(true)) {
|
|
16341
|
+
this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
|
|
16342
|
+
return null;
|
|
16343
|
+
}
|
|
16271
16344
|
const loggedInAccounts = this.getAllAccounts();
|
|
16272
|
-
const
|
|
16273
|
-
const useNative =
|
|
16345
|
+
const platformBrokerRequest = this.browserStorage.getCachedNativeRequest();
|
|
16346
|
+
const useNative = platformBrokerRequest &&
|
|
16274
16347
|
NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeExtensionProvider) &&
|
|
16275
16348
|
this.nativeExtensionProvider &&
|
|
16276
16349
|
!hash;
|
|
16277
|
-
|
|
16278
|
-
? request?.correlationId
|
|
16279
|
-
: this.browserStorage.getTemporaryCache(TemporaryCacheKeys.CORRELATION_ID, true) || "";
|
|
16280
|
-
const rootMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenRedirect, correlationId);
|
|
16350
|
+
let rootMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenRedirect, platformBrokerRequest?.correlationId || "");
|
|
16281
16351
|
this.eventHandler.emitEvent(EventType.HANDLE_REDIRECT_START, exports.InteractionType.Redirect);
|
|
16282
16352
|
let redirectResponse;
|
|
16283
16353
|
if (useNative && this.nativeExtensionProvider) {
|
|
16284
16354
|
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,
|
|
16355
|
+
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
16356
|
redirectResponse = invokeAsync(nativeClient.handleRedirectPromise.bind(nativeClient), PerformanceEvents.HandleNativeRedirectPromiseMeasurement, this.logger, this.performanceClient, rootMeasurement.event.correlationId)(this.performanceClient, rootMeasurement.event.correlationId);
|
|
16287
16357
|
}
|
|
16288
16358
|
else {
|
|
16359
|
+
const [standardRequest, codeVerifier] = this.browserStorage.getCachedRequest();
|
|
16360
|
+
const correlationId = standardRequest.correlationId;
|
|
16361
|
+
// Reset rootMeasurement now that we have correlationId
|
|
16362
|
+
rootMeasurement.discard();
|
|
16363
|
+
rootMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenRedirect, correlationId);
|
|
16289
16364
|
this.logger.trace("handleRedirectPromise - acquiring token from web flow");
|
|
16290
16365
|
const redirectClient = this.createRedirectClient(correlationId);
|
|
16291
|
-
redirectResponse = invokeAsync(redirectClient.handleRedirectPromise.bind(redirectClient), PerformanceEvents.HandleRedirectPromiseMeasurement, this.logger, this.performanceClient, rootMeasurement.event.correlationId)(hash, rootMeasurement);
|
|
16366
|
+
redirectResponse = invokeAsync(redirectClient.handleRedirectPromise.bind(redirectClient), PerformanceEvents.HandleRedirectPromiseMeasurement, this.logger, this.performanceClient, rootMeasurement.event.correlationId)(hash, standardRequest, codeVerifier, rootMeasurement);
|
|
16292
16367
|
}
|
|
16293
16368
|
return redirectResponse
|
|
16294
16369
|
.then((result) => {
|
|
16295
16370
|
if (result) {
|
|
16371
|
+
this.browserStorage.resetRequestCache();
|
|
16296
16372
|
// Emit login event if number of accounts change
|
|
16297
16373
|
const isLoggingIn = loggedInAccounts.length < this.getAllAccounts().length;
|
|
16298
16374
|
if (isLoggingIn) {
|
|
@@ -16324,6 +16400,7 @@ class StandardController {
|
|
|
16324
16400
|
return result;
|
|
16325
16401
|
})
|
|
16326
16402
|
.catch((e) => {
|
|
16403
|
+
this.browserStorage.resetRequestCache();
|
|
16327
16404
|
const eventError = e;
|
|
16328
16405
|
// Emit login event if there is an account
|
|
16329
16406
|
if (loggedInAccounts.length > 0) {
|
|
@@ -16417,7 +16494,6 @@ class StandardController {
|
|
|
16417
16494
|
const redirectClient = this.createRedirectClient(correlationId);
|
|
16418
16495
|
return redirectClient.acquireToken(request);
|
|
16419
16496
|
}
|
|
16420
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
16421
16497
|
throw e;
|
|
16422
16498
|
});
|
|
16423
16499
|
}
|
|
@@ -16428,6 +16504,7 @@ class StandardController {
|
|
|
16428
16504
|
return await result;
|
|
16429
16505
|
}
|
|
16430
16506
|
catch (e) {
|
|
16507
|
+
this.browserStorage.resetRequestCache();
|
|
16431
16508
|
atrMeasurement.end({ success: false }, e);
|
|
16432
16509
|
if (isLoggedIn) {
|
|
16433
16510
|
this.eventHandler.emitEvent(EventType.ACQUIRE_TOKEN_FAILURE, exports.InteractionType.Redirect, null, e);
|
|
@@ -16479,7 +16556,6 @@ class StandardController {
|
|
|
16479
16556
|
correlationId,
|
|
16480
16557
|
}, ApiId.acquireTokenPopup)
|
|
16481
16558
|
.then((response) => {
|
|
16482
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
16483
16559
|
atPopupMeasurement.end({
|
|
16484
16560
|
success: true,
|
|
16485
16561
|
isNativeBroker: true,
|
|
@@ -16499,7 +16575,6 @@ class StandardController {
|
|
|
16499
16575
|
const popupClient = this.createPopupClient(correlationId);
|
|
16500
16576
|
return popupClient.acquireToken(request, pkce);
|
|
16501
16577
|
}
|
|
16502
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
16503
16578
|
throw e;
|
|
16504
16579
|
});
|
|
16505
16580
|
}
|
|
@@ -16540,8 +16615,12 @@ class StandardController {
|
|
|
16540
16615
|
// Since this function is syncronous we need to reject
|
|
16541
16616
|
return Promise.reject(e);
|
|
16542
16617
|
})
|
|
16543
|
-
.finally(() =>
|
|
16544
|
-
this.
|
|
16618
|
+
.finally(async () => {
|
|
16619
|
+
this.browserStorage.setInteractionInProgress(false);
|
|
16620
|
+
if (this.config.system.asyncPopups) {
|
|
16621
|
+
await this.preGeneratePkceCodes(correlationId);
|
|
16622
|
+
}
|
|
16623
|
+
});
|
|
16545
16624
|
}
|
|
16546
16625
|
trackPageVisibilityWithMeasurement() {
|
|
16547
16626
|
const measurement = this.ssoSilentMeasurement ||
|
|
@@ -16844,7 +16923,9 @@ class StandardController {
|
|
|
16844
16923
|
preflightCheck$1(this.initialized);
|
|
16845
16924
|
this.browserStorage.setInteractionInProgress(true);
|
|
16846
16925
|
const popupClient = this.createPopupClient(correlationId);
|
|
16847
|
-
return popupClient.logout(logoutRequest)
|
|
16926
|
+
return popupClient.logout(logoutRequest).finally(() => {
|
|
16927
|
+
this.browserStorage.setInteractionInProgress(false);
|
|
16928
|
+
});
|
|
16848
16929
|
}
|
|
16849
16930
|
catch (e) {
|
|
16850
16931
|
// Since this function is syncronous we need to reject
|