@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.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @azure/msal-browser v4.
|
|
1
|
+
/*! @azure/msal-browser v4.9.0 2025-03-25 */
|
|
2
2
|
'use strict';
|
|
3
3
|
(function (global, factory) {
|
|
4
4
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.msal = {}));
|
|
7
7
|
})(this, (function (exports) { 'use strict';
|
|
8
8
|
|
|
9
|
-
/*! @azure/msal-common v15.
|
|
9
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
10
10
|
/*
|
|
11
11
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
12
12
|
* Licensed under the MIT License.
|
|
@@ -41,11 +41,8 @@
|
|
|
41
41
|
PROFILE_SCOPE: "profile",
|
|
42
42
|
OFFLINE_ACCESS_SCOPE: "offline_access",
|
|
43
43
|
EMAIL_SCOPE: "email",
|
|
44
|
-
// Default response type for authorization code flow
|
|
45
|
-
CODE_RESPONSE_TYPE: "code",
|
|
46
44
|
CODE_GRANT_TYPE: "authorization_code",
|
|
47
45
|
RT_GRANT_TYPE: "refresh_token",
|
|
48
|
-
FRAGMENT_RESPONSE_MODE: "fragment",
|
|
49
46
|
S256_CODE_CHALLENGE_METHOD: "S256",
|
|
50
47
|
URL_FORM_CONTENT_TYPE: "application/x-www-form-urlencoded;charset=utf-8",
|
|
51
48
|
AUTHORIZATION_PENDING: "authorization_pending",
|
|
@@ -65,8 +62,6 @@
|
|
|
65
62
|
"login.microsoft.com",
|
|
66
63
|
"sts.windows.net",
|
|
67
64
|
],
|
|
68
|
-
TOKEN_RESPONSE_TYPE: "token",
|
|
69
|
-
ID_TOKEN_RESPONSE_TYPE: "id_token",
|
|
70
65
|
SHR_NONCE_VALIDITY: 240,
|
|
71
66
|
INVALID_INSTANCE: "invalid_instance",
|
|
72
67
|
};
|
|
@@ -150,8 +145,17 @@
|
|
|
150
145
|
PLAIN: "plain",
|
|
151
146
|
S256: "S256",
|
|
152
147
|
};
|
|
148
|
+
/**
|
|
149
|
+
* Allowed values for response_type
|
|
150
|
+
*/
|
|
151
|
+
const OAuthResponseType = {
|
|
152
|
+
CODE: "code",
|
|
153
|
+
IDTOKEN_TOKEN: "id_token token",
|
|
154
|
+
IDTOKEN_TOKEN_REFRESHTOKEN: "id_token token refresh_token",
|
|
155
|
+
};
|
|
153
156
|
/**
|
|
154
157
|
* allowed values for server response type
|
|
158
|
+
* @deprecated Use ResponseMode instead
|
|
155
159
|
*/
|
|
156
160
|
const ServerResponseType = {
|
|
157
161
|
QUERY: "query",
|
|
@@ -161,7 +165,8 @@
|
|
|
161
165
|
* allowed values for response_mode
|
|
162
166
|
*/
|
|
163
167
|
const ResponseMode = {
|
|
164
|
-
|
|
168
|
+
QUERY: "query",
|
|
169
|
+
FRAGMENT: "fragment",
|
|
165
170
|
FORM_POST: "form_post",
|
|
166
171
|
};
|
|
167
172
|
/**
|
|
@@ -303,7 +308,7 @@
|
|
|
303
308
|
// Token renewal offset default in seconds
|
|
304
309
|
const DEFAULT_TOKEN_RENEWAL_OFFSET_SEC = 300;
|
|
305
310
|
|
|
306
|
-
/*! @azure/msal-common v15.
|
|
311
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
307
312
|
/*
|
|
308
313
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
309
314
|
* Licensed under the MIT License.
|
|
@@ -320,7 +325,7 @@
|
|
|
320
325
|
unexpectedError: unexpectedError
|
|
321
326
|
});
|
|
322
327
|
|
|
323
|
-
/*! @azure/msal-common v15.
|
|
328
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
324
329
|
|
|
325
330
|
/*
|
|
326
331
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -369,7 +374,7 @@
|
|
|
369
374
|
: AuthErrorMessages[code]);
|
|
370
375
|
}
|
|
371
376
|
|
|
372
|
-
/*! @azure/msal-common v15.
|
|
377
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
373
378
|
/*
|
|
374
379
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
375
380
|
* Licensed under the MIT License.
|
|
@@ -467,7 +472,7 @@
|
|
|
467
472
|
userTimeoutReached: userTimeoutReached
|
|
468
473
|
});
|
|
469
474
|
|
|
470
|
-
/*! @azure/msal-common v15.
|
|
475
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
471
476
|
|
|
472
477
|
/*
|
|
473
478
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -719,7 +724,7 @@
|
|
|
719
724
|
return new ClientAuthError(errorCode, additionalMessage);
|
|
720
725
|
}
|
|
721
726
|
|
|
722
|
-
/*! @azure/msal-common v15.
|
|
727
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
723
728
|
|
|
724
729
|
/*
|
|
725
730
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -758,7 +763,7 @@
|
|
|
758
763
|
},
|
|
759
764
|
};
|
|
760
765
|
|
|
761
|
-
/*! @azure/msal-common v15.
|
|
766
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
762
767
|
|
|
763
768
|
/*
|
|
764
769
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -949,12 +954,12 @@
|
|
|
949
954
|
}
|
|
950
955
|
}
|
|
951
956
|
|
|
952
|
-
/*! @azure/msal-common v15.
|
|
957
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
953
958
|
/* eslint-disable header/header */
|
|
954
959
|
const name$1 = "@azure/msal-common";
|
|
955
|
-
const version$1 = "15.
|
|
960
|
+
const version$1 = "15.4.0";
|
|
956
961
|
|
|
957
|
-
/*! @azure/msal-common v15.
|
|
962
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
958
963
|
/*
|
|
959
964
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
960
965
|
* Licensed under the MIT License.
|
|
@@ -974,7 +979,7 @@
|
|
|
974
979
|
AzureUsGovernment: "https://login.microsoftonline.us",
|
|
975
980
|
};
|
|
976
981
|
|
|
977
|
-
/*! @azure/msal-common v15.
|
|
982
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
978
983
|
|
|
979
984
|
/*
|
|
980
985
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1035,7 +1040,7 @@
|
|
|
1035
1040
|
}
|
|
1036
1041
|
}
|
|
1037
1042
|
|
|
1038
|
-
/*! @azure/msal-common v15.
|
|
1043
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1039
1044
|
/*
|
|
1040
1045
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
1041
1046
|
* Licensed under the MIT License.
|
|
@@ -1090,7 +1095,7 @@
|
|
|
1090
1095
|
return cachedAtSec > nowSeconds();
|
|
1091
1096
|
}
|
|
1092
1097
|
|
|
1093
|
-
/*! @azure/msal-common v15.
|
|
1098
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1094
1099
|
|
|
1095
1100
|
/*
|
|
1096
1101
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1417,7 +1422,7 @@
|
|
|
1417
1422
|
return metadata.expiresAt <= nowSeconds();
|
|
1418
1423
|
}
|
|
1419
1424
|
|
|
1420
|
-
/*! @azure/msal-common v15.
|
|
1425
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1421
1426
|
/*
|
|
1422
1427
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
1423
1428
|
* Licensed under the MIT License.
|
|
@@ -1471,7 +1476,7 @@
|
|
|
1471
1476
|
urlParseError: urlParseError
|
|
1472
1477
|
});
|
|
1473
1478
|
|
|
1474
|
-
/*! @azure/msal-common v15.
|
|
1479
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1475
1480
|
|
|
1476
1481
|
/*
|
|
1477
1482
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1609,7 +1614,7 @@
|
|
|
1609
1614
|
return new ClientConfigurationError(errorCode);
|
|
1610
1615
|
}
|
|
1611
1616
|
|
|
1612
|
-
/*! @azure/msal-common v15.
|
|
1617
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1613
1618
|
/*
|
|
1614
1619
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
1615
1620
|
* Licensed under the MIT License.
|
|
@@ -1706,7 +1711,7 @@
|
|
|
1706
1711
|
}
|
|
1707
1712
|
}
|
|
1708
1713
|
|
|
1709
|
-
/*! @azure/msal-common v15.
|
|
1714
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1710
1715
|
|
|
1711
1716
|
/*
|
|
1712
1717
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1897,7 +1902,7 @@
|
|
|
1897
1902
|
}
|
|
1898
1903
|
}
|
|
1899
1904
|
|
|
1900
|
-
/*! @azure/msal-common v15.
|
|
1905
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1901
1906
|
|
|
1902
1907
|
/*
|
|
1903
1908
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -1937,7 +1942,7 @@
|
|
|
1937
1942
|
};
|
|
1938
1943
|
}
|
|
1939
1944
|
|
|
1940
|
-
/*! @azure/msal-common v15.
|
|
1945
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
1941
1946
|
/*
|
|
1942
1947
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
1943
1948
|
* Licensed under the MIT License.
|
|
@@ -2016,7 +2021,7 @@
|
|
|
2016
2021
|
return updatedAccountInfo;
|
|
2017
2022
|
}
|
|
2018
2023
|
|
|
2019
|
-
/*! @azure/msal-common v15.
|
|
2024
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2020
2025
|
/*
|
|
2021
2026
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2022
2027
|
* Licensed under the MIT License.
|
|
@@ -2031,7 +2036,7 @@
|
|
|
2031
2036
|
Ciam: 3,
|
|
2032
2037
|
};
|
|
2033
2038
|
|
|
2034
|
-
/*! @azure/msal-common v15.
|
|
2039
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2035
2040
|
/*
|
|
2036
2041
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2037
2042
|
* Licensed under the MIT License.
|
|
@@ -2053,7 +2058,7 @@
|
|
|
2053
2058
|
return null;
|
|
2054
2059
|
}
|
|
2055
2060
|
|
|
2056
|
-
/*! @azure/msal-common v15.
|
|
2061
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2057
2062
|
/*
|
|
2058
2063
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2059
2064
|
* Licensed under the MIT License.
|
|
@@ -2062,11 +2067,22 @@
|
|
|
2062
2067
|
* Protocol modes supported by MSAL.
|
|
2063
2068
|
*/
|
|
2064
2069
|
const ProtocolMode = {
|
|
2070
|
+
/**
|
|
2071
|
+
* Auth Code + PKCE with Entra ID (formerly AAD) specific optimizations and features
|
|
2072
|
+
*/
|
|
2065
2073
|
AAD: "AAD",
|
|
2074
|
+
/**
|
|
2075
|
+
* Auth Code + PKCE without Entra ID specific optimizations and features. For use only with non-Microsoft owned authorities.
|
|
2076
|
+
* Support is limited for this mode.
|
|
2077
|
+
*/
|
|
2066
2078
|
OIDC: "OIDC",
|
|
2079
|
+
/**
|
|
2080
|
+
* Encrypted Authorize Response (EAR) with Entra ID specific optimizations and features
|
|
2081
|
+
*/
|
|
2082
|
+
EAR: "EAR",
|
|
2067
2083
|
};
|
|
2068
2084
|
|
|
2069
|
-
/*! @azure/msal-common v15.
|
|
2085
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2070
2086
|
|
|
2071
2087
|
/*
|
|
2072
2088
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2162,11 +2178,11 @@
|
|
|
2162
2178
|
if (authority.authorityType === AuthorityType.Adfs) {
|
|
2163
2179
|
account.authorityType = CacheAccountType.ADFS_ACCOUNT_TYPE;
|
|
2164
2180
|
}
|
|
2165
|
-
else if (authority.protocolMode === ProtocolMode.
|
|
2166
|
-
account.authorityType = CacheAccountType.
|
|
2181
|
+
else if (authority.protocolMode === ProtocolMode.OIDC) {
|
|
2182
|
+
account.authorityType = CacheAccountType.GENERIC_ACCOUNT_TYPE;
|
|
2167
2183
|
}
|
|
2168
2184
|
else {
|
|
2169
|
-
account.authorityType = CacheAccountType.
|
|
2185
|
+
account.authorityType = CacheAccountType.MSSTS_ACCOUNT_TYPE;
|
|
2170
2186
|
}
|
|
2171
2187
|
let clientInfo;
|
|
2172
2188
|
if (accountDetails.clientInfo && base64Decode) {
|
|
@@ -2309,7 +2325,7 @@
|
|
|
2309
2325
|
}
|
|
2310
2326
|
}
|
|
2311
2327
|
|
|
2312
|
-
/*! @azure/msal-common v15.
|
|
2328
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2313
2329
|
|
|
2314
2330
|
/*
|
|
2315
2331
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2344,6 +2360,7 @@
|
|
|
2344
2360
|
const deserializedHash = Object.fromEntries(new URLSearchParams(normalizedResponse));
|
|
2345
2361
|
// Check for known response properties
|
|
2346
2362
|
if (deserializedHash.code ||
|
|
2363
|
+
deserializedHash.ear_jwe ||
|
|
2347
2364
|
deserializedHash.error ||
|
|
2348
2365
|
deserializedHash.error_description ||
|
|
2349
2366
|
deserializedHash.state) {
|
|
@@ -2366,7 +2383,7 @@
|
|
|
2366
2383
|
return queryParameterArray.join("&");
|
|
2367
2384
|
}
|
|
2368
2385
|
|
|
2369
|
-
/*! @azure/msal-common v15.
|
|
2386
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2370
2387
|
|
|
2371
2388
|
/*
|
|
2372
2389
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2530,7 +2547,7 @@
|
|
|
2530
2547
|
}
|
|
2531
2548
|
}
|
|
2532
2549
|
|
|
2533
|
-
/*! @azure/msal-common v15.
|
|
2550
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2534
2551
|
|
|
2535
2552
|
/*
|
|
2536
2553
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2670,7 +2687,7 @@
|
|
|
2670
2687
|
return null;
|
|
2671
2688
|
}
|
|
2672
2689
|
|
|
2673
|
-
/*! @azure/msal-common v15.
|
|
2690
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2674
2691
|
/*
|
|
2675
2692
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2676
2693
|
* Licensed under the MIT License.
|
|
@@ -2678,7 +2695,7 @@
|
|
|
2678
2695
|
const cacheQuotaExceededErrorCode = "cache_quota_exceeded";
|
|
2679
2696
|
const cacheUnknownErrorCode = "cache_error_unknown";
|
|
2680
2697
|
|
|
2681
|
-
/*! @azure/msal-common v15.
|
|
2698
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2682
2699
|
|
|
2683
2700
|
/*
|
|
2684
2701
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -2705,7 +2722,7 @@
|
|
|
2705
2722
|
}
|
|
2706
2723
|
}
|
|
2707
2724
|
|
|
2708
|
-
/*! @azure/msal-common v15.
|
|
2725
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
2709
2726
|
|
|
2710
2727
|
/*
|
|
2711
2728
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -3890,7 +3907,7 @@
|
|
|
3890
3907
|
}
|
|
3891
3908
|
}
|
|
3892
3909
|
|
|
3893
|
-
/*! @azure/msal-common v15.
|
|
3910
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
3894
3911
|
|
|
3895
3912
|
/*
|
|
3896
3913
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -3989,7 +4006,7 @@
|
|
|
3989
4006
|
return (config.authOptions.authority.options.protocolMode === ProtocolMode.OIDC);
|
|
3990
4007
|
}
|
|
3991
4008
|
|
|
3992
|
-
/*! @azure/msal-common v15.
|
|
4009
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
3993
4010
|
/*
|
|
3994
4011
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3995
4012
|
* Licensed under the MIT License.
|
|
@@ -3999,7 +4016,7 @@
|
|
|
3999
4016
|
UPN: "UPN",
|
|
4000
4017
|
};
|
|
4001
4018
|
|
|
4002
|
-
/*! @azure/msal-common v15.
|
|
4019
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4003
4020
|
/*
|
|
4004
4021
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4005
4022
|
* Licensed under the MIT License.
|
|
@@ -4045,9 +4062,11 @@
|
|
|
4045
4062
|
const X_CLIENT_EXTRA_SKU = "x-client-xtra-sku";
|
|
4046
4063
|
const BROKER_CLIENT_ID = "brk_client_id";
|
|
4047
4064
|
const BROKER_REDIRECT_URI = "brk_redirect_uri";
|
|
4048
|
-
const INSTANCE_AWARE = "instance_aware";
|
|
4065
|
+
const INSTANCE_AWARE = "instance_aware";
|
|
4066
|
+
const EAR_JWK = "ear_jwk";
|
|
4067
|
+
const EAR_JWE_CRYPTO = "ear_jwe_crypto";
|
|
4049
4068
|
|
|
4050
|
-
/*! @azure/msal-common v15.
|
|
4069
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4051
4070
|
|
|
4052
4071
|
/*
|
|
4053
4072
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -4066,10 +4085,12 @@
|
|
|
4066
4085
|
}
|
|
4067
4086
|
}
|
|
4068
4087
|
/**
|
|
4069
|
-
*
|
|
4088
|
+
* Add the given response_type
|
|
4089
|
+
* @param parameters
|
|
4090
|
+
* @param responseType
|
|
4070
4091
|
*/
|
|
4071
|
-
function
|
|
4072
|
-
parameters.set(RESPONSE_TYPE,
|
|
4092
|
+
function addResponseType(parameters, responseType) {
|
|
4093
|
+
parameters.set(RESPONSE_TYPE, responseType);
|
|
4073
4094
|
}
|
|
4074
4095
|
/**
|
|
4075
4096
|
* add response_mode. defaults to query.
|
|
@@ -4400,9 +4421,20 @@
|
|
|
4400
4421
|
if (!parameters.has(BROKER_REDIRECT_URI)) {
|
|
4401
4422
|
parameters.set(BROKER_REDIRECT_URI, brokerRedirectUri);
|
|
4402
4423
|
}
|
|
4424
|
+
}
|
|
4425
|
+
/**
|
|
4426
|
+
* Add EAR (Encrypted Authorize Response) request parameters
|
|
4427
|
+
* @param parameters
|
|
4428
|
+
* @param jwk
|
|
4429
|
+
*/
|
|
4430
|
+
function addEARParameters(parameters, jwk) {
|
|
4431
|
+
parameters.set(EAR_JWK, encodeURIComponent(jwk));
|
|
4432
|
+
// ear_jwe_crypto will always have value: {"alg":"dir","enc":"A256GCM"} so we can hardcode this
|
|
4433
|
+
const jweCryptoB64Encoded = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0";
|
|
4434
|
+
parameters.set(EAR_JWE_CRYPTO, jweCryptoB64Encoded);
|
|
4403
4435
|
}
|
|
4404
4436
|
|
|
4405
|
-
/*! @azure/msal-common v15.
|
|
4437
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4406
4438
|
/*
|
|
4407
4439
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4408
4440
|
* Licensed under the MIT License.
|
|
@@ -4414,7 +4446,7 @@
|
|
|
4414
4446
|
response.hasOwnProperty("jwks_uri"));
|
|
4415
4447
|
}
|
|
4416
4448
|
|
|
4417
|
-
/*! @azure/msal-common v15.
|
|
4449
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4418
4450
|
/*
|
|
4419
4451
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4420
4452
|
* Licensed under the MIT License.
|
|
@@ -4424,7 +4456,7 @@
|
|
|
4424
4456
|
response.hasOwnProperty("metadata"));
|
|
4425
4457
|
}
|
|
4426
4458
|
|
|
4427
|
-
/*! @azure/msal-common v15.
|
|
4459
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4428
4460
|
/*
|
|
4429
4461
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4430
4462
|
* Licensed under the MIT License.
|
|
@@ -4434,7 +4466,7 @@
|
|
|
4434
4466
|
response.hasOwnProperty("error_description"));
|
|
4435
4467
|
}
|
|
4436
4468
|
|
|
4437
|
-
/*! @azure/msal-common v15.
|
|
4469
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4438
4470
|
/*
|
|
4439
4471
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4440
4472
|
* Licensed under the MIT License.
|
|
@@ -4620,6 +4652,9 @@
|
|
|
4620
4652
|
*/
|
|
4621
4653
|
HandleCodeResponseFromServer: "handleCodeResponseFromServer",
|
|
4622
4654
|
HandleCodeResponse: "handleCodeResponse",
|
|
4655
|
+
HandleResponseEar: "handleResponseEar",
|
|
4656
|
+
HandleResponsePlatformBroker: "handleResponsePlatformBroker",
|
|
4657
|
+
HandleResponseCode: "handleResponseCode",
|
|
4623
4658
|
UpdateTokenEndpointAuthority: "updateTokenEndpointAuthority",
|
|
4624
4659
|
/**
|
|
4625
4660
|
* APIs in Authorization Code Client (msal-common)
|
|
@@ -4686,6 +4721,8 @@
|
|
|
4686
4721
|
UrlEncodeArr: "urlEncodeArr",
|
|
4687
4722
|
Encrypt: "encrypt",
|
|
4688
4723
|
Decrypt: "decrypt",
|
|
4724
|
+
GenerateEarKey: "generateEarKey",
|
|
4725
|
+
DecryptEarResponse: "decryptEarResponse",
|
|
4689
4726
|
};
|
|
4690
4727
|
const PerformanceEventAbbreviations = new Map([
|
|
4691
4728
|
[PerformanceEvents.AcquireTokenByCode, "ATByCode"],
|
|
@@ -4803,6 +4840,12 @@
|
|
|
4803
4840
|
"HandleCodeResFromServer",
|
|
4804
4841
|
],
|
|
4805
4842
|
[PerformanceEvents.HandleCodeResponse, "HandleCodeResp"],
|
|
4843
|
+
[PerformanceEvents.HandleResponseEar, "HandleRespEar"],
|
|
4844
|
+
[PerformanceEvents.HandleResponseCode, "HandleRespCode"],
|
|
4845
|
+
[
|
|
4846
|
+
PerformanceEvents.HandleResponsePlatformBroker,
|
|
4847
|
+
"HandleRespPlatBroker",
|
|
4848
|
+
],
|
|
4806
4849
|
[PerformanceEvents.UpdateTokenEndpointAuthority, "UpdTEndpointAuth"],
|
|
4807
4850
|
[PerformanceEvents.AuthClientAcquireToken, "AuthClientAT"],
|
|
4808
4851
|
[PerformanceEvents.AuthClientExecuteTokenRequest, "AuthClientExecTReq"],
|
|
@@ -4905,6 +4948,8 @@
|
|
|
4905
4948
|
[PerformanceEvents.UrlEncodeArr, "urlEncArr"],
|
|
4906
4949
|
[PerformanceEvents.Encrypt, "encrypt"],
|
|
4907
4950
|
[PerformanceEvents.Decrypt, "decrypt"],
|
|
4951
|
+
[PerformanceEvents.GenerateEarKey, "genEarKey"],
|
|
4952
|
+
[PerformanceEvents.DecryptEarResponse, "decryptEarResp"],
|
|
4908
4953
|
]);
|
|
4909
4954
|
/**
|
|
4910
4955
|
* State of the performance event.
|
|
@@ -4934,7 +4979,7 @@
|
|
|
4934
4979
|
"encryptedCacheExpiredCount",
|
|
4935
4980
|
]);
|
|
4936
4981
|
|
|
4937
|
-
/*! @azure/msal-common v15.
|
|
4982
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
4938
4983
|
/*
|
|
4939
4984
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4940
4985
|
* Licensed under the MIT License.
|
|
@@ -5030,7 +5075,7 @@
|
|
|
5030
5075
|
};
|
|
5031
5076
|
};
|
|
5032
5077
|
|
|
5033
|
-
/*! @azure/msal-common v15.
|
|
5078
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
5034
5079
|
|
|
5035
5080
|
/*
|
|
5036
5081
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -5139,7 +5184,7 @@
|
|
|
5139
5184
|
},
|
|
5140
5185
|
};
|
|
5141
5186
|
|
|
5142
|
-
/*! @azure/msal-common v15.
|
|
5187
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
5143
5188
|
|
|
5144
5189
|
/*
|
|
5145
5190
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -5317,7 +5362,7 @@
|
|
|
5317
5362
|
return (authorityUri.PathSegments.length === 1 &&
|
|
5318
5363
|
!Authority.reservedTenantDomains.has(authorityUri.PathSegments[0]) &&
|
|
5319
5364
|
this.getAuthorityType(authorityUri) === AuthorityType.Default &&
|
|
5320
|
-
this.protocolMode
|
|
5365
|
+
this.protocolMode !== ProtocolMode.OIDC);
|
|
5321
5366
|
}
|
|
5322
5367
|
/**
|
|
5323
5368
|
* Replaces tenant in url path with current tenant. Defaults to common.
|
|
@@ -5364,7 +5409,7 @@
|
|
|
5364
5409
|
const canonicalAuthorityHost = this.hostnameAndPort;
|
|
5365
5410
|
if (this.canonicalAuthority.endsWith("v2.0/") ||
|
|
5366
5411
|
this.authorityType === AuthorityType.Adfs ||
|
|
5367
|
-
(this.protocolMode
|
|
5412
|
+
(this.protocolMode === ProtocolMode.OIDC &&
|
|
5368
5413
|
!this.isAliasOfKnownMicrosoftAuthority(canonicalAuthorityHost))) {
|
|
5369
5414
|
return `${this.canonicalAuthority}.well-known/openid-configuration`;
|
|
5370
5415
|
}
|
|
@@ -5978,7 +6023,7 @@
|
|
|
5978
6023
|
};
|
|
5979
6024
|
}
|
|
5980
6025
|
|
|
5981
|
-
/*! @azure/msal-common v15.
|
|
6026
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
5982
6027
|
|
|
5983
6028
|
/*
|
|
5984
6029
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6009,7 +6054,7 @@
|
|
|
6009
6054
|
}
|
|
6010
6055
|
}
|
|
6011
6056
|
|
|
6012
|
-
/*! @azure/msal-common v15.
|
|
6057
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6013
6058
|
|
|
6014
6059
|
/*
|
|
6015
6060
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6028,7 +6073,7 @@
|
|
|
6028
6073
|
}
|
|
6029
6074
|
}
|
|
6030
6075
|
|
|
6031
|
-
/*! @azure/msal-common v15.
|
|
6076
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6032
6077
|
/*
|
|
6033
6078
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
6034
6079
|
* Licensed under the MIT License.
|
|
@@ -6049,7 +6094,7 @@
|
|
|
6049
6094
|
};
|
|
6050
6095
|
}
|
|
6051
6096
|
|
|
6052
|
-
/*! @azure/msal-common v15.
|
|
6097
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6053
6098
|
|
|
6054
6099
|
/*
|
|
6055
6100
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6136,7 +6181,7 @@
|
|
|
6136
6181
|
}
|
|
6137
6182
|
}
|
|
6138
6183
|
|
|
6139
|
-
/*! @azure/msal-common v15.
|
|
6184
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6140
6185
|
|
|
6141
6186
|
/*
|
|
6142
6187
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6166,7 +6211,7 @@
|
|
|
6166
6211
|
return new NetworkError(error, httpStatus, responseHeaders);
|
|
6167
6212
|
}
|
|
6168
6213
|
|
|
6169
|
-
/*! @azure/msal-common v15.
|
|
6214
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6170
6215
|
|
|
6171
6216
|
/*
|
|
6172
6217
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6314,7 +6359,7 @@
|
|
|
6314
6359
|
}
|
|
6315
6360
|
}
|
|
6316
6361
|
|
|
6317
|
-
/*! @azure/msal-common v15.
|
|
6362
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6318
6363
|
/*
|
|
6319
6364
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
6320
6365
|
* Licensed under the MIT License.
|
|
@@ -6340,7 +6385,7 @@
|
|
|
6340
6385
|
refreshTokenExpired: refreshTokenExpired
|
|
6341
6386
|
});
|
|
6342
6387
|
|
|
6343
|
-
/*! @azure/msal-common v15.
|
|
6388
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6344
6389
|
|
|
6345
6390
|
/*
|
|
6346
6391
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6428,7 +6473,7 @@
|
|
|
6428
6473
|
return new InteractionRequiredAuthError(errorCode, InteractionRequiredAuthErrorMessages[errorCode]);
|
|
6429
6474
|
}
|
|
6430
6475
|
|
|
6431
|
-
/*! @azure/msal-common v15.
|
|
6476
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6432
6477
|
|
|
6433
6478
|
/*
|
|
6434
6479
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6500,7 +6545,7 @@
|
|
|
6500
6545
|
}
|
|
6501
6546
|
}
|
|
6502
6547
|
|
|
6503
|
-
/*! @azure/msal-common v15.
|
|
6548
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6504
6549
|
|
|
6505
6550
|
/*
|
|
6506
6551
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6584,7 +6629,7 @@
|
|
|
6584
6629
|
}
|
|
6585
6630
|
}
|
|
6586
6631
|
|
|
6587
|
-
/*! @azure/msal-common v15.
|
|
6632
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6588
6633
|
/*
|
|
6589
6634
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
6590
6635
|
* Licensed under the MIT License.
|
|
@@ -6611,7 +6656,7 @@
|
|
|
6611
6656
|
}
|
|
6612
6657
|
}
|
|
6613
6658
|
|
|
6614
|
-
/*! @azure/msal-common v15.
|
|
6659
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6615
6660
|
|
|
6616
6661
|
/*
|
|
6617
6662
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -6942,7 +6987,7 @@
|
|
|
6942
6987
|
return baseAccount;
|
|
6943
6988
|
}
|
|
6944
6989
|
|
|
6945
|
-
/*! @azure/msal-common v15.
|
|
6990
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
6946
6991
|
|
|
6947
6992
|
/*
|
|
6948
6993
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7009,7 +7054,7 @@
|
|
|
7009
7054
|
}
|
|
7010
7055
|
}
|
|
7011
7056
|
|
|
7012
|
-
/*! @azure/msal-common v15.
|
|
7057
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7013
7058
|
/*
|
|
7014
7059
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
7015
7060
|
* Licensed under the MIT License.
|
|
@@ -7027,7 +7072,7 @@
|
|
|
7027
7072
|
}
|
|
7028
7073
|
}
|
|
7029
7074
|
|
|
7030
|
-
/*! @azure/msal-common v15.
|
|
7075
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7031
7076
|
|
|
7032
7077
|
/*
|
|
7033
7078
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7260,7 +7305,7 @@
|
|
|
7260
7305
|
}
|
|
7261
7306
|
}
|
|
7262
7307
|
|
|
7263
|
-
/*! @azure/msal-common v15.
|
|
7308
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7264
7309
|
|
|
7265
7310
|
/*
|
|
7266
7311
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7469,7 +7514,7 @@
|
|
|
7469
7514
|
}
|
|
7470
7515
|
}
|
|
7471
7516
|
|
|
7472
|
-
/*! @azure/msal-common v15.
|
|
7517
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7473
7518
|
|
|
7474
7519
|
/*
|
|
7475
7520
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7567,7 +7612,7 @@
|
|
|
7567
7612
|
}
|
|
7568
7613
|
}
|
|
7569
7614
|
|
|
7570
|
-
/*! @azure/msal-common v15.
|
|
7615
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7571
7616
|
|
|
7572
7617
|
/*
|
|
7573
7618
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7582,7 +7627,7 @@
|
|
|
7582
7627
|
},
|
|
7583
7628
|
};
|
|
7584
7629
|
|
|
7585
|
-
/*! @azure/msal-common v15.
|
|
7630
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7586
7631
|
|
|
7587
7632
|
/*
|
|
7588
7633
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7711,10 +7756,10 @@
|
|
|
7711
7756
|
if (request.embeddedClientId) {
|
|
7712
7757
|
addBrokerParameters(parameters, authOptions.clientId, authOptions.redirectUri);
|
|
7713
7758
|
}
|
|
7714
|
-
|
|
7715
|
-
|
|
7716
|
-
|
|
7717
|
-
|
|
7759
|
+
// If extraQueryParameters includes instance_aware its value will be added when extraQueryParameters are added
|
|
7760
|
+
if (authOptions.instanceAware &&
|
|
7761
|
+
(!request.extraQueryParameters ||
|
|
7762
|
+
!Object.keys(request.extraQueryParameters).includes(INSTANCE_AWARE))) {
|
|
7718
7763
|
addInstanceAware(parameters);
|
|
7719
7764
|
}
|
|
7720
7765
|
return parameters;
|
|
@@ -7806,7 +7851,7 @@
|
|
|
7806
7851
|
return account.idTokenClaims?.login_hint || null;
|
|
7807
7852
|
}
|
|
7808
7853
|
|
|
7809
|
-
/*! @azure/msal-common v15.
|
|
7854
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7810
7855
|
|
|
7811
7856
|
/*
|
|
7812
7857
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -7864,7 +7909,7 @@
|
|
|
7864
7909
|
}
|
|
7865
7910
|
}
|
|
7866
7911
|
|
|
7867
|
-
/*! @azure/msal-common v15.
|
|
7912
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
7868
7913
|
|
|
7869
7914
|
/*
|
|
7870
7915
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8127,7 +8172,7 @@
|
|
|
8127
8172
|
}
|
|
8128
8173
|
}
|
|
8129
8174
|
|
|
8130
|
-
/*! @azure/msal-common v15.
|
|
8175
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
8131
8176
|
/*
|
|
8132
8177
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
8133
8178
|
* Licensed under the MIT License.
|
|
@@ -8135,7 +8180,7 @@
|
|
|
8135
8180
|
const missingKidError = "missing_kid_error";
|
|
8136
8181
|
const missingAlgError = "missing_alg_error";
|
|
8137
8182
|
|
|
8138
|
-
/*! @azure/msal-common v15.
|
|
8183
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
8139
8184
|
|
|
8140
8185
|
/*
|
|
8141
8186
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8160,7 +8205,7 @@
|
|
|
8160
8205
|
return new JoseHeaderError(code, JoseHeaderErrorMessages[code]);
|
|
8161
8206
|
}
|
|
8162
8207
|
|
|
8163
|
-
/*! @azure/msal-common v15.
|
|
8208
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
8164
8209
|
|
|
8165
8210
|
/*
|
|
8166
8211
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8200,7 +8245,7 @@
|
|
|
8200
8245
|
}
|
|
8201
8246
|
}
|
|
8202
8247
|
|
|
8203
|
-
/*! @azure/msal-common v15.
|
|
8248
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
8204
8249
|
|
|
8205
8250
|
/*
|
|
8206
8251
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8279,7 +8324,7 @@
|
|
|
8279
8324
|
}
|
|
8280
8325
|
}
|
|
8281
8326
|
|
|
8282
|
-
/*! @azure/msal-common v15.
|
|
8327
|
+
/*! @azure/msal-common v15.4.0 2025-03-25 */
|
|
8283
8328
|
|
|
8284
8329
|
/*
|
|
8285
8330
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -8893,6 +8938,8 @@
|
|
|
8893
8938
|
* Licensed under the MIT License.
|
|
8894
8939
|
*/
|
|
8895
8940
|
const pkceNotCreated = "pkce_not_created";
|
|
8941
|
+
const earJwkEmpty = "ear_jwk_empty";
|
|
8942
|
+
const earJweEmpty = "ear_jwe_empty";
|
|
8896
8943
|
const cryptoNonExistent = "crypto_nonexistent";
|
|
8897
8944
|
const emptyNavigateUri = "empty_navigate_uri";
|
|
8898
8945
|
const hashEmptyError = "hash_empty_error";
|
|
@@ -8915,7 +8962,6 @@
|
|
|
8915
8962
|
const silentPromptValueError = "silent_prompt_value_error";
|
|
8916
8963
|
const noTokenRequestCacheError = "no_token_request_cache_error";
|
|
8917
8964
|
const unableToParseTokenRequestCacheError = "unable_to_parse_token_request_cache_error";
|
|
8918
|
-
const noCachedAuthorityError = "no_cached_authority_error";
|
|
8919
8965
|
const authRequestNotSetError = "auth_request_not_set_error";
|
|
8920
8966
|
const invalidCacheType = "invalid_cache_type";
|
|
8921
8967
|
const nonBrowserEnvironment = "non_browser_environment";
|
|
@@ -8939,7 +8985,8 @@
|
|
|
8939
8985
|
const invalidBase64String = "invalid_base64_string";
|
|
8940
8986
|
const invalidPopTokenRequest = "invalid_pop_token_request";
|
|
8941
8987
|
const failedToBuildHeaders = "failed_to_build_headers";
|
|
8942
|
-
const failedToParseHeaders = "failed_to_parse_headers";
|
|
8988
|
+
const failedToParseHeaders = "failed_to_parse_headers";
|
|
8989
|
+
const failedToDecryptEarResponse = "failed_to_decrypt_ear_response";
|
|
8943
8990
|
|
|
8944
8991
|
var BrowserAuthErrorCodes = /*#__PURE__*/Object.freeze({
|
|
8945
8992
|
__proto__: null,
|
|
@@ -8952,9 +8999,12 @@
|
|
|
8952
8999
|
cryptoNonExistent: cryptoNonExistent,
|
|
8953
9000
|
databaseNotOpen: databaseNotOpen,
|
|
8954
9001
|
databaseUnavailable: databaseUnavailable,
|
|
9002
|
+
earJweEmpty: earJweEmpty,
|
|
9003
|
+
earJwkEmpty: earJwkEmpty,
|
|
8955
9004
|
emptyNavigateUri: emptyNavigateUri,
|
|
8956
9005
|
emptyWindowError: emptyWindowError,
|
|
8957
9006
|
failedToBuildHeaders: failedToBuildHeaders,
|
|
9007
|
+
failedToDecryptEarResponse: failedToDecryptEarResponse,
|
|
8958
9008
|
failedToParseHeaders: failedToParseHeaders,
|
|
8959
9009
|
failedToParseResponse: failedToParseResponse,
|
|
8960
9010
|
getRequestFailed: getRequestFailed,
|
|
@@ -8972,7 +9022,6 @@
|
|
|
8972
9022
|
nativeHandshakeTimeout: nativeHandshakeTimeout,
|
|
8973
9023
|
nativePromptNotSupported: nativePromptNotSupported,
|
|
8974
9024
|
noAccountError: noAccountError,
|
|
8975
|
-
noCachedAuthorityError: noCachedAuthorityError,
|
|
8976
9025
|
noNetworkConnectivity: noNetworkConnectivity,
|
|
8977
9026
|
noStateInHash: noStateInHash,
|
|
8978
9027
|
noTokenRequestCacheError: noTokenRequestCacheError,
|
|
@@ -9003,6 +9052,8 @@
|
|
|
9003
9052
|
*/
|
|
9004
9053
|
const BrowserAuthErrorMessages = {
|
|
9005
9054
|
[pkceNotCreated]: "The PKCE code challenge and verifier could not be generated.",
|
|
9055
|
+
[earJwkEmpty]: "No EAR encryption key provided. This is unexpected.",
|
|
9056
|
+
[earJweEmpty]: "Server response does not contain ear_jwe property. This is unexpected.",
|
|
9006
9057
|
[cryptoNonExistent]: "The crypto object or function is not available.",
|
|
9007
9058
|
[emptyNavigateUri]: "Navigation URI is empty. Please check stack trace for more info.",
|
|
9008
9059
|
[hashEmptyError]: `Hash value cannot be processed because it is empty. Please verify that your redirectUri is not clearing the hash. ${ErrorLink}`,
|
|
@@ -9025,7 +9076,6 @@
|
|
|
9025
9076
|
[silentPromptValueError]: "The value given for the prompt value is not valid for silent requests - must be set to 'none' or 'no_session'.",
|
|
9026
9077
|
[noTokenRequestCacheError]: "No token request found in cache.",
|
|
9027
9078
|
[unableToParseTokenRequestCacheError]: "The cached token request could not be parsed.",
|
|
9028
|
-
[noCachedAuthorityError]: "No cached authority found.",
|
|
9029
9079
|
[authRequestNotSetError]: "Auth Request not set. Please ensure initiateAuthRequest was called from the InteractionHandler",
|
|
9030
9080
|
[invalidCacheType]: "Invalid cache type",
|
|
9031
9081
|
[nonBrowserEnvironment]: "Login and token requests are not supported in non-browser environments.",
|
|
@@ -9050,6 +9100,7 @@
|
|
|
9050
9100
|
[invalidPopTokenRequest]: "Invalid PoP token request. The request should not have both a popKid value and signPopToken set to true.",
|
|
9051
9101
|
[failedToBuildHeaders]: "Failed to build request headers object.",
|
|
9052
9102
|
[failedToParseHeaders]: "Failed to parse response headers",
|
|
9103
|
+
[failedToDecryptEarResponse]: "Failed to decrypt ear response",
|
|
9053
9104
|
};
|
|
9054
9105
|
/**
|
|
9055
9106
|
* BrowserAuthErrorMessage class containing string constants used by error codes and messages.
|
|
@@ -9152,10 +9203,6 @@
|
|
|
9152
9203
|
code: unableToParseTokenRequestCacheError,
|
|
9153
9204
|
desc: BrowserAuthErrorMessages[unableToParseTokenRequestCacheError],
|
|
9154
9205
|
},
|
|
9155
|
-
noCachedAuthorityError: {
|
|
9156
|
-
code: noCachedAuthorityError,
|
|
9157
|
-
desc: BrowserAuthErrorMessages[noCachedAuthorityError],
|
|
9158
|
-
},
|
|
9159
9206
|
authRequestNotSet: {
|
|
9160
9207
|
code: authRequestNotSetError,
|
|
9161
9208
|
desc: BrowserAuthErrorMessages[authRequestNotSetError],
|
|
@@ -9323,21 +9370,12 @@
|
|
|
9323
9370
|
* Temporary cache keys for MSAL, deleted after any request.
|
|
9324
9371
|
*/
|
|
9325
9372
|
const TemporaryCacheKeys = {
|
|
9326
|
-
AUTHORITY: "authority",
|
|
9327
|
-
ACQUIRE_TOKEN_ACCOUNT: "acquireToken.account",
|
|
9328
|
-
SESSION_STATE: "session.state",
|
|
9329
|
-
REQUEST_STATE: "request.state",
|
|
9330
|
-
NONCE_IDTOKEN: "nonce.id_token",
|
|
9331
9373
|
ORIGIN_URI: "request.origin",
|
|
9332
|
-
RENEW_STATUS: "token.renew.status",
|
|
9333
9374
|
URL_HASH: "urlHash",
|
|
9334
9375
|
REQUEST_PARAMS: "request.params",
|
|
9335
|
-
|
|
9376
|
+
VERIFIER: "code.verifier",
|
|
9336
9377
|
INTERACTION_STATUS_KEY: "interaction.status",
|
|
9337
|
-
CCS_CREDENTIAL: "ccs.credential",
|
|
9338
|
-
CORRELATION_ID: "request.correlationId",
|
|
9339
9378
|
NATIVE_REQUEST: "request.native",
|
|
9340
|
-
REDIRECT_CONTEXT: "request.redirect.context",
|
|
9341
9379
|
};
|
|
9342
9380
|
const StaticCacheKeys = {
|
|
9343
9381
|
ACCOUNT_KEYS: "msal.account.keys",
|
|
@@ -9707,6 +9745,69 @@
|
|
|
9707
9745
|
async function sign(key, data) {
|
|
9708
9746
|
return window.crypto.subtle.sign(keygenAlgorithmOptions, key, data);
|
|
9709
9747
|
}
|
|
9748
|
+
/**
|
|
9749
|
+
* Generates Base64 encoded jwk used in the Encrypted Authorize Response (EAR) flow
|
|
9750
|
+
*/
|
|
9751
|
+
async function generateEarKey() {
|
|
9752
|
+
const key = await generateBaseKey();
|
|
9753
|
+
const keyStr = urlEncodeArr(new Uint8Array(key));
|
|
9754
|
+
const jwk = {
|
|
9755
|
+
alg: "dir",
|
|
9756
|
+
kty: "oct",
|
|
9757
|
+
k: keyStr,
|
|
9758
|
+
};
|
|
9759
|
+
return base64Encode(JSON.stringify(jwk));
|
|
9760
|
+
}
|
|
9761
|
+
/**
|
|
9762
|
+
* Parses earJwk for encryption key and returns CryptoKey object
|
|
9763
|
+
* @param earJwk
|
|
9764
|
+
* @returns
|
|
9765
|
+
*/
|
|
9766
|
+
async function importEarKey(earJwk) {
|
|
9767
|
+
const b64DecodedJwk = base64Decode(earJwk);
|
|
9768
|
+
const jwkJson = JSON.parse(b64DecodedJwk);
|
|
9769
|
+
const rawKey = jwkJson.k;
|
|
9770
|
+
const keyBuffer = base64DecToArr(rawKey);
|
|
9771
|
+
return window.crypto.subtle.importKey(RAW, keyBuffer, AES_GCM, false, [
|
|
9772
|
+
DECRYPT,
|
|
9773
|
+
]);
|
|
9774
|
+
}
|
|
9775
|
+
/**
|
|
9776
|
+
* Decrypt ear_jwe response returned in the Encrypted Authorize Response (EAR) flow
|
|
9777
|
+
* @param earJwk
|
|
9778
|
+
* @param earJwe
|
|
9779
|
+
* @returns
|
|
9780
|
+
*/
|
|
9781
|
+
async function decryptEarResponse(earJwk, earJwe) {
|
|
9782
|
+
const earJweParts = earJwe.split(".");
|
|
9783
|
+
if (earJweParts.length !== 5) {
|
|
9784
|
+
throw createBrowserAuthError(failedToDecryptEarResponse, "jwe_length");
|
|
9785
|
+
}
|
|
9786
|
+
const key = await importEarKey(earJwk).catch(() => {
|
|
9787
|
+
throw createBrowserAuthError(failedToDecryptEarResponse, "import_key");
|
|
9788
|
+
});
|
|
9789
|
+
try {
|
|
9790
|
+
const header = new TextEncoder().encode(earJweParts[0]);
|
|
9791
|
+
const iv = base64DecToArr(earJweParts[2]);
|
|
9792
|
+
const ciphertext = base64DecToArr(earJweParts[3]);
|
|
9793
|
+
const tag = base64DecToArr(earJweParts[4]);
|
|
9794
|
+
const tagLengthBits = tag.byteLength * 8;
|
|
9795
|
+
// Concat ciphertext and tag
|
|
9796
|
+
const encryptedData = new Uint8Array(ciphertext.length + tag.length);
|
|
9797
|
+
encryptedData.set(ciphertext);
|
|
9798
|
+
encryptedData.set(tag, ciphertext.length);
|
|
9799
|
+
const decryptedData = await window.crypto.subtle.decrypt({
|
|
9800
|
+
name: AES_GCM,
|
|
9801
|
+
iv: iv,
|
|
9802
|
+
tagLength: tagLengthBits,
|
|
9803
|
+
additionalData: header,
|
|
9804
|
+
}, key, encryptedData);
|
|
9805
|
+
return new TextDecoder().decode(decryptedData);
|
|
9806
|
+
}
|
|
9807
|
+
catch (e) {
|
|
9808
|
+
throw createBrowserAuthError(failedToDecryptEarResponse, "decrypt");
|
|
9809
|
+
}
|
|
9810
|
+
}
|
|
9710
9811
|
/**
|
|
9711
9812
|
* Generates symmetric base encryption key. This may be stored as all encryption/decryption keys will be derived from this one.
|
|
9712
9813
|
*/
|
|
@@ -10292,9 +10393,9 @@
|
|
|
10292
10393
|
const logger = new Logger(providedSystemOptions.loggerOptions);
|
|
10293
10394
|
logger.warning(JSON.stringify(createClientConfigurationError(cannotSetOIDCOptions)));
|
|
10294
10395
|
}
|
|
10295
|
-
// Throw an error if user has set allowPlatformBroker to true
|
|
10396
|
+
// Throw an error if user has set allowPlatformBroker to true with OIDC protocol mode
|
|
10296
10397
|
if (userInputAuth?.protocolMode &&
|
|
10297
|
-
userInputAuth.protocolMode
|
|
10398
|
+
userInputAuth.protocolMode === ProtocolMode.OIDC &&
|
|
10298
10399
|
providedSystemOptions?.allowPlatformBroker) {
|
|
10299
10400
|
throw createClientConfigurationError(cannotAllowPlatformBroker);
|
|
10300
10401
|
}
|
|
@@ -10311,12 +10412,21 @@
|
|
|
10311
10412
|
system: providedSystemOptions,
|
|
10312
10413
|
telemetry: { ...DEFAULT_TELEMETRY_OPTIONS, ...userInputTelemetry },
|
|
10313
10414
|
};
|
|
10415
|
+
/**
|
|
10416
|
+
* Temporarily disable EAR until implementation is complete
|
|
10417
|
+
* TODO: Remove this
|
|
10418
|
+
*/
|
|
10419
|
+
if (overlayedConfig.auth.protocolMode === ProtocolMode.EAR) {
|
|
10420
|
+
const logger = new Logger(providedSystemOptions.loggerOptions);
|
|
10421
|
+
logger.warning("EAR Protocol Mode is not yet supported. Overriding to use PKCE auth");
|
|
10422
|
+
overlayedConfig.auth.protocolMode = ProtocolMode.AAD;
|
|
10423
|
+
}
|
|
10314
10424
|
return overlayedConfig;
|
|
10315
10425
|
}
|
|
10316
10426
|
|
|
10317
10427
|
/* eslint-disable header/header */
|
|
10318
10428
|
const name = "@azure/msal-browser";
|
|
10319
|
-
const version = "4.
|
|
10429
|
+
const version = "4.9.0";
|
|
10320
10430
|
|
|
10321
10431
|
/*
|
|
10322
10432
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -11637,28 +11747,6 @@
|
|
|
11637
11747
|
}
|
|
11638
11748
|
}
|
|
11639
11749
|
|
|
11640
|
-
/*
|
|
11641
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
11642
|
-
* Licensed under the MIT License.
|
|
11643
|
-
*/
|
|
11644
|
-
/**
|
|
11645
|
-
* Extracts the BrowserStateObject from the state string.
|
|
11646
|
-
* @param browserCrypto
|
|
11647
|
-
* @param state
|
|
11648
|
-
*/
|
|
11649
|
-
function extractBrowserRequestState(browserCrypto, state) {
|
|
11650
|
-
if (!state) {
|
|
11651
|
-
return null;
|
|
11652
|
-
}
|
|
11653
|
-
try {
|
|
11654
|
-
const requestStateObj = ProtocolUtils.parseRequestState(browserCrypto, state);
|
|
11655
|
-
return requestStateObj.libraryState.meta;
|
|
11656
|
-
}
|
|
11657
|
-
catch (e) {
|
|
11658
|
-
throw createClientAuthError(invalidState);
|
|
11659
|
-
}
|
|
11660
|
-
}
|
|
11661
|
-
|
|
11662
11750
|
/*
|
|
11663
11751
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
11664
11752
|
* Licensed under the MIT License.
|
|
@@ -12358,177 +12446,53 @@
|
|
|
12358
12446
|
}
|
|
12359
12447
|
return JSON.stringify(key);
|
|
12360
12448
|
}
|
|
12361
|
-
/**
|
|
12362
|
-
* Create authorityKey to cache authority
|
|
12363
|
-
* @param state
|
|
12364
|
-
*/
|
|
12365
|
-
generateAuthorityKey(stateString) {
|
|
12366
|
-
const { libraryState: { id: stateId }, } = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString);
|
|
12367
|
-
return this.generateCacheKey(`${TemporaryCacheKeys.AUTHORITY}.${stateId}`);
|
|
12368
|
-
}
|
|
12369
|
-
/**
|
|
12370
|
-
* Create Nonce key to cache nonce
|
|
12371
|
-
* @param state
|
|
12372
|
-
*/
|
|
12373
|
-
generateNonceKey(stateString) {
|
|
12374
|
-
const { libraryState: { id: stateId }, } = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString);
|
|
12375
|
-
return this.generateCacheKey(`${TemporaryCacheKeys.NONCE_IDTOKEN}.${stateId}`);
|
|
12376
|
-
}
|
|
12377
|
-
/**
|
|
12378
|
-
* Creates full cache key for the request state
|
|
12379
|
-
* @param stateString State string for the request
|
|
12380
|
-
*/
|
|
12381
|
-
generateStateKey(stateString) {
|
|
12382
|
-
// Use the library state id to key temp storage for uniqueness for multiple concurrent requests
|
|
12383
|
-
const { libraryState: { id: stateId }, } = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString);
|
|
12384
|
-
return this.generateCacheKey(`${TemporaryCacheKeys.REQUEST_STATE}.${stateId}`);
|
|
12385
|
-
}
|
|
12386
|
-
/**
|
|
12387
|
-
* Gets the cached authority based on the cached state. Returns empty if no cached state found.
|
|
12388
|
-
*/
|
|
12389
|
-
getCachedAuthority(cachedState) {
|
|
12390
|
-
const stateCacheKey = this.generateStateKey(cachedState);
|
|
12391
|
-
const state = this.getTemporaryCache(stateCacheKey);
|
|
12392
|
-
if (!state) {
|
|
12393
|
-
return null;
|
|
12394
|
-
}
|
|
12395
|
-
const authorityCacheKey = this.generateAuthorityKey(state);
|
|
12396
|
-
return this.getTemporaryCache(authorityCacheKey);
|
|
12397
|
-
}
|
|
12398
|
-
/**
|
|
12399
|
-
* Updates account, authority, and state in cache
|
|
12400
|
-
* @param serverAuthenticationRequest
|
|
12401
|
-
* @param account
|
|
12402
|
-
*/
|
|
12403
|
-
updateCacheEntries(state, nonce, authorityInstance, loginHint, account) {
|
|
12404
|
-
this.logger.trace("BrowserCacheManager.updateCacheEntries called");
|
|
12405
|
-
// Cache the request state
|
|
12406
|
-
const stateCacheKey = this.generateStateKey(state);
|
|
12407
|
-
this.setTemporaryCache(stateCacheKey, state, false);
|
|
12408
|
-
// Cache the nonce
|
|
12409
|
-
const nonceCacheKey = this.generateNonceKey(state);
|
|
12410
|
-
this.setTemporaryCache(nonceCacheKey, nonce, false);
|
|
12411
|
-
// Cache authorityKey
|
|
12412
|
-
const authorityCacheKey = this.generateAuthorityKey(state);
|
|
12413
|
-
this.setTemporaryCache(authorityCacheKey, authorityInstance, false);
|
|
12414
|
-
if (account) {
|
|
12415
|
-
const ccsCredential = {
|
|
12416
|
-
credential: account.homeAccountId,
|
|
12417
|
-
type: CcsCredentialType.HOME_ACCOUNT_ID,
|
|
12418
|
-
};
|
|
12419
|
-
this.setTemporaryCache(TemporaryCacheKeys.CCS_CREDENTIAL, JSON.stringify(ccsCredential), true);
|
|
12420
|
-
}
|
|
12421
|
-
else if (loginHint) {
|
|
12422
|
-
const ccsCredential = {
|
|
12423
|
-
credential: loginHint,
|
|
12424
|
-
type: CcsCredentialType.UPN,
|
|
12425
|
-
};
|
|
12426
|
-
this.setTemporaryCache(TemporaryCacheKeys.CCS_CREDENTIAL, JSON.stringify(ccsCredential), true);
|
|
12427
|
-
}
|
|
12428
|
-
}
|
|
12429
12449
|
/**
|
|
12430
12450
|
* Reset all temporary cache items
|
|
12431
12451
|
* @param state
|
|
12432
12452
|
*/
|
|
12433
|
-
resetRequestCache(
|
|
12453
|
+
resetRequestCache() {
|
|
12434
12454
|
this.logger.trace("BrowserCacheManager.resetRequestCache called");
|
|
12435
|
-
// check state and remove associated cache items
|
|
12436
|
-
if (state) {
|
|
12437
|
-
this.temporaryCacheStorage.getKeys().forEach((key) => {
|
|
12438
|
-
if (key.indexOf(state) !== -1) {
|
|
12439
|
-
this.removeTemporaryItem(key);
|
|
12440
|
-
}
|
|
12441
|
-
});
|
|
12442
|
-
// delete generic interactive request parameters
|
|
12443
|
-
this.removeTemporaryItem(this.generateStateKey(state));
|
|
12444
|
-
this.removeTemporaryItem(this.generateNonceKey(state));
|
|
12445
|
-
this.removeTemporaryItem(this.generateAuthorityKey(state));
|
|
12446
|
-
}
|
|
12447
12455
|
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.REQUEST_PARAMS));
|
|
12456
|
+
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.VERIFIER));
|
|
12448
12457
|
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.ORIGIN_URI));
|
|
12449
12458
|
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.URL_HASH));
|
|
12450
|
-
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.CORRELATION_ID));
|
|
12451
|
-
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.CCS_CREDENTIAL));
|
|
12452
12459
|
this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST));
|
|
12453
12460
|
this.setInteractionInProgress(false);
|
|
12454
12461
|
}
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
* @param stateString
|
|
12458
|
-
*/
|
|
12459
|
-
cleanRequestByState(stateString) {
|
|
12460
|
-
this.logger.trace("BrowserCacheManager.cleanRequestByState called");
|
|
12461
|
-
// Interaction is completed - remove interaction status.
|
|
12462
|
-
if (stateString) {
|
|
12463
|
-
const stateKey = this.generateStateKey(stateString);
|
|
12464
|
-
const cachedState = this.temporaryCacheStorage.getItem(stateKey);
|
|
12465
|
-
this.logger.infoPii(`BrowserCacheManager.cleanRequestByState: Removing temporary cache items for state: ${cachedState}`);
|
|
12466
|
-
this.resetRequestCache(cachedState || Constants.EMPTY_STRING);
|
|
12467
|
-
}
|
|
12468
|
-
}
|
|
12469
|
-
/**
|
|
12470
|
-
* Looks in temporary cache for any state values with the provided interactionType and removes all temporary cache items for that state
|
|
12471
|
-
* Used in scenarios where temp cache needs to be cleaned but state is not known, such as clicking browser back button.
|
|
12472
|
-
* @param interactionType
|
|
12473
|
-
*/
|
|
12474
|
-
cleanRequestByInteractionType(interactionType) {
|
|
12475
|
-
this.logger.trace("BrowserCacheManager.cleanRequestByInteractionType called");
|
|
12476
|
-
// Loop through all keys to find state key
|
|
12477
|
-
this.temporaryCacheStorage.getKeys().forEach((key) => {
|
|
12478
|
-
// If this key is not the state key, move on
|
|
12479
|
-
if (key.indexOf(TemporaryCacheKeys.REQUEST_STATE) === -1) {
|
|
12480
|
-
return;
|
|
12481
|
-
}
|
|
12482
|
-
// Retrieve state value, return if not a valid value
|
|
12483
|
-
const stateValue = this.temporaryCacheStorage.getItem(key);
|
|
12484
|
-
if (!stateValue) {
|
|
12485
|
-
return;
|
|
12486
|
-
}
|
|
12487
|
-
// Extract state and ensure it matches given InteractionType, then clean request cache
|
|
12488
|
-
const parsedState = extractBrowserRequestState(this.cryptoImpl, stateValue);
|
|
12489
|
-
if (parsedState &&
|
|
12490
|
-
parsedState.interactionType === interactionType) {
|
|
12491
|
-
this.logger.infoPii(`BrowserCacheManager.cleanRequestByInteractionType: Removing temporary cache items for state: ${stateValue}`);
|
|
12492
|
-
this.resetRequestCache(stateValue);
|
|
12493
|
-
}
|
|
12494
|
-
});
|
|
12495
|
-
this.setInteractionInProgress(false);
|
|
12496
|
-
}
|
|
12497
|
-
cacheCodeRequest(authCodeRequest) {
|
|
12498
|
-
this.logger.trace("BrowserCacheManager.cacheCodeRequest called");
|
|
12462
|
+
cacheAuthorizeRequest(authCodeRequest, codeVerifier) {
|
|
12463
|
+
this.logger.trace("BrowserCacheManager.cacheAuthorizeRequest called");
|
|
12499
12464
|
const encodedValue = base64Encode(JSON.stringify(authCodeRequest));
|
|
12500
12465
|
this.setTemporaryCache(TemporaryCacheKeys.REQUEST_PARAMS, encodedValue, true);
|
|
12466
|
+
if (codeVerifier) {
|
|
12467
|
+
const encodedVerifier = base64Encode(codeVerifier);
|
|
12468
|
+
this.setTemporaryCache(TemporaryCacheKeys.VERIFIER, encodedVerifier, true);
|
|
12469
|
+
}
|
|
12501
12470
|
}
|
|
12502
12471
|
/**
|
|
12503
12472
|
* Gets the token exchange parameters from the cache. Throws an error if nothing is found.
|
|
12504
12473
|
*/
|
|
12505
|
-
getCachedRequest(
|
|
12474
|
+
getCachedRequest() {
|
|
12506
12475
|
this.logger.trace("BrowserCacheManager.getCachedRequest called");
|
|
12507
12476
|
// Get token request from cache and parse as TokenExchangeParameters.
|
|
12508
12477
|
const encodedTokenRequest = this.getTemporaryCache(TemporaryCacheKeys.REQUEST_PARAMS, true);
|
|
12509
12478
|
if (!encodedTokenRequest) {
|
|
12510
12479
|
throw createBrowserAuthError(noTokenRequestCacheError);
|
|
12511
12480
|
}
|
|
12481
|
+
const encodedVerifier = this.getTemporaryCache(TemporaryCacheKeys.VERIFIER, true);
|
|
12512
12482
|
let parsedRequest;
|
|
12483
|
+
let verifier = "";
|
|
12513
12484
|
try {
|
|
12514
12485
|
parsedRequest = JSON.parse(base64Decode(encodedTokenRequest));
|
|
12486
|
+
if (encodedVerifier) {
|
|
12487
|
+
verifier = base64Decode(encodedVerifier);
|
|
12488
|
+
}
|
|
12515
12489
|
}
|
|
12516
12490
|
catch (e) {
|
|
12517
12491
|
this.logger.errorPii(`Attempted to parse: ${encodedTokenRequest}`);
|
|
12518
12492
|
this.logger.error(`Parsing cached token request threw with error: ${e}`);
|
|
12519
12493
|
throw createBrowserAuthError(unableToParseTokenRequestCacheError);
|
|
12520
12494
|
}
|
|
12521
|
-
|
|
12522
|
-
// Get cached authority and use if no authority is cached with request.
|
|
12523
|
-
if (!parsedRequest.authority) {
|
|
12524
|
-
const authorityCacheKey = this.generateAuthorityKey(state);
|
|
12525
|
-
const cachedAuthority = this.getTemporaryCache(authorityCacheKey);
|
|
12526
|
-
if (!cachedAuthority) {
|
|
12527
|
-
throw createBrowserAuthError(noCachedAuthorityError);
|
|
12528
|
-
}
|
|
12529
|
-
parsedRequest.authority = cachedAuthority;
|
|
12530
|
-
}
|
|
12531
|
-
return parsedRequest;
|
|
12495
|
+
return [parsedRequest, verifier];
|
|
12532
12496
|
}
|
|
12533
12497
|
/**
|
|
12534
12498
|
* Gets cached native request for redirect flows
|
|
@@ -13354,1083 +13318,1103 @@
|
|
|
13354
13318
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13355
13319
|
* Licensed under the MIT License.
|
|
13356
13320
|
*/
|
|
13357
|
-
class
|
|
13321
|
+
class NativeMessageHandler {
|
|
13322
|
+
constructor(logger, handshakeTimeoutMs, performanceClient, extensionId) {
|
|
13323
|
+
this.logger = logger;
|
|
13324
|
+
this.handshakeTimeoutMs = handshakeTimeoutMs;
|
|
13325
|
+
this.extensionId = extensionId;
|
|
13326
|
+
this.resolvers = new Map(); // Used for non-handshake messages
|
|
13327
|
+
this.handshakeResolvers = new Map(); // Used for handshake messages
|
|
13328
|
+
this.messageChannel = new MessageChannel();
|
|
13329
|
+
this.windowListener = this.onWindowMessage.bind(this); // Window event callback doesn't have access to 'this' unless it's bound
|
|
13330
|
+
this.performanceClient = performanceClient;
|
|
13331
|
+
this.handshakeEvent = performanceClient.startMeasurement(PerformanceEvents.NativeMessageHandlerHandshake);
|
|
13332
|
+
}
|
|
13358
13333
|
/**
|
|
13359
|
-
*
|
|
13360
|
-
* @param
|
|
13334
|
+
* Sends a given message to the extension and resolves with the extension response
|
|
13335
|
+
* @param body
|
|
13361
13336
|
*/
|
|
13362
|
-
async
|
|
13363
|
-
this.
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
|
|
13367
|
-
|
|
13368
|
-
|
|
13369
|
-
|
|
13370
|
-
|
|
13337
|
+
async sendMessage(body) {
|
|
13338
|
+
this.logger.trace("NativeMessageHandler - sendMessage called.");
|
|
13339
|
+
const req = {
|
|
13340
|
+
channel: NativeConstants.CHANNEL_ID,
|
|
13341
|
+
extensionId: this.extensionId,
|
|
13342
|
+
responseId: createNewGuid(),
|
|
13343
|
+
body: body,
|
|
13344
|
+
};
|
|
13345
|
+
this.logger.trace("NativeMessageHandler - Sending request to browser extension");
|
|
13346
|
+
this.logger.tracePii(`NativeMessageHandler - Sending request to browser extension: ${JSON.stringify(req)}`);
|
|
13347
|
+
this.messageChannel.port1.postMessage(req);
|
|
13348
|
+
return new Promise((resolve, reject) => {
|
|
13349
|
+
this.resolvers.set(req.responseId, { resolve, reject });
|
|
13371
13350
|
});
|
|
13372
|
-
|
|
13373
|
-
|
|
13351
|
+
}
|
|
13352
|
+
/**
|
|
13353
|
+
* Returns an instance of the MessageHandler that has successfully established a connection with an extension
|
|
13354
|
+
* @param {Logger} logger
|
|
13355
|
+
* @param {number} handshakeTimeoutMs
|
|
13356
|
+
* @param {IPerformanceClient} performanceClient
|
|
13357
|
+
* @param {ICrypto} crypto
|
|
13358
|
+
*/
|
|
13359
|
+
static async createProvider(logger, handshakeTimeoutMs, performanceClient) {
|
|
13360
|
+
logger.trace("NativeMessageHandler - createProvider called.");
|
|
13374
13361
|
try {
|
|
13375
|
-
const
|
|
13376
|
-
|
|
13377
|
-
|
|
13378
|
-
fromCache: true,
|
|
13379
|
-
}, silentRequest.correlationId);
|
|
13380
|
-
return authResponse;
|
|
13362
|
+
const preferredProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient, NativeConstants.PREFERRED_EXTENSION_ID);
|
|
13363
|
+
await preferredProvider.sendHandshakeRequest();
|
|
13364
|
+
return preferredProvider;
|
|
13381
13365
|
}
|
|
13382
|
-
catch (
|
|
13383
|
-
|
|
13384
|
-
|
|
13385
|
-
|
|
13386
|
-
|
|
13387
|
-
throw error;
|
|
13366
|
+
catch (e) {
|
|
13367
|
+
// If preferred extension fails for whatever reason, fallback to using any installed extension
|
|
13368
|
+
const backupProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient);
|
|
13369
|
+
await backupProvider.sendHandshakeRequest();
|
|
13370
|
+
return backupProvider;
|
|
13388
13371
|
}
|
|
13389
13372
|
}
|
|
13390
13373
|
/**
|
|
13391
|
-
*
|
|
13392
|
-
* @param logoutRequest
|
|
13374
|
+
* Send handshake request helper.
|
|
13393
13375
|
*/
|
|
13394
|
-
|
|
13395
|
-
this.logger.
|
|
13396
|
-
|
|
13397
|
-
|
|
13398
|
-
|
|
13399
|
-
|
|
13400
|
-
|
|
13401
|
-
|
|
13402
|
-
|
|
13403
|
-
|
|
13404
|
-
|
|
13405
|
-
|
|
13406
|
-
|
|
13407
|
-
|
|
13408
|
-
|
|
13409
|
-
this.accountId = accountId;
|
|
13410
|
-
this.nativeMessageHandler = provider;
|
|
13411
|
-
this.nativeStorageManager = nativeStorageImpl;
|
|
13412
|
-
this.silentCacheClient = new SilentCacheClient(config, this.nativeStorageManager, browserCrypto, logger, eventHandler, navigationClient, performanceClient, provider, correlationId);
|
|
13413
|
-
const extensionName = this.nativeMessageHandler.getExtensionId() ===
|
|
13414
|
-
NativeConstants.PREFERRED_EXTENSION_ID
|
|
13415
|
-
? "chrome"
|
|
13416
|
-
: this.nativeMessageHandler.getExtensionId()?.length
|
|
13417
|
-
? "unknown"
|
|
13418
|
-
: undefined;
|
|
13419
|
-
this.skus = ServerTelemetryManager.makeExtraSkuString({
|
|
13420
|
-
libraryName: BrowserConstants.MSAL_SKU,
|
|
13421
|
-
libraryVersion: version,
|
|
13422
|
-
extensionName: extensionName,
|
|
13423
|
-
extensionVersion: this.nativeMessageHandler.getExtensionVersion(),
|
|
13376
|
+
async sendHandshakeRequest() {
|
|
13377
|
+
this.logger.trace("NativeMessageHandler - sendHandshakeRequest called.");
|
|
13378
|
+
// Register this event listener before sending handshake
|
|
13379
|
+
window.addEventListener("message", this.windowListener, false); // false is important, because content script message processing should work first
|
|
13380
|
+
const req = {
|
|
13381
|
+
channel: NativeConstants.CHANNEL_ID,
|
|
13382
|
+
extensionId: this.extensionId,
|
|
13383
|
+
responseId: createNewGuid(),
|
|
13384
|
+
body: {
|
|
13385
|
+
method: NativeExtensionMethod.HandshakeRequest,
|
|
13386
|
+
},
|
|
13387
|
+
};
|
|
13388
|
+
this.handshakeEvent.add({
|
|
13389
|
+
extensionId: this.extensionId,
|
|
13390
|
+
extensionHandshakeTimeoutMs: this.handshakeTimeoutMs,
|
|
13424
13391
|
});
|
|
13425
|
-
|
|
13426
|
-
|
|
13427
|
-
* Adds SKUs to request extra query parameters
|
|
13428
|
-
* @param request {NativeTokenRequest}
|
|
13429
|
-
* @private
|
|
13430
|
-
*/
|
|
13431
|
-
addRequestSKUs(request) {
|
|
13432
|
-
request.extraParameters = {
|
|
13433
|
-
...request.extraParameters,
|
|
13434
|
-
[X_CLIENT_EXTRA_SKU]: this.skus,
|
|
13392
|
+
this.messageChannel.port1.onmessage = (event) => {
|
|
13393
|
+
this.onChannelMessage(event);
|
|
13435
13394
|
};
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
|
|
13441
|
-
|
|
13442
|
-
|
|
13443
|
-
|
|
13444
|
-
|
|
13445
|
-
|
|
13446
|
-
|
|
13447
|
-
|
|
13448
|
-
|
|
13449
|
-
// initialize native request
|
|
13450
|
-
const nativeRequest = await this.initializeNativeRequest(request);
|
|
13451
|
-
// check if the tokens can be retrieved from internal cache
|
|
13452
|
-
try {
|
|
13453
|
-
const result = await this.acquireTokensFromCache(this.accountId, nativeRequest);
|
|
13454
|
-
nativeATMeasurement.end({
|
|
13455
|
-
success: true,
|
|
13456
|
-
isNativeBroker: false,
|
|
13457
|
-
fromCache: true,
|
|
13458
|
-
});
|
|
13459
|
-
return result;
|
|
13460
|
-
}
|
|
13461
|
-
catch (e) {
|
|
13462
|
-
if (cacheLookupPolicy === CacheLookupPolicy.AccessToken) {
|
|
13463
|
-
this.logger.info("MSAL internal Cache does not contain tokens, return error as per cache policy");
|
|
13464
|
-
throw e;
|
|
13465
|
-
}
|
|
13466
|
-
// continue with a native call for any and all errors
|
|
13467
|
-
this.logger.info("MSAL internal Cache does not contain tokens, proceed to make a native call");
|
|
13468
|
-
}
|
|
13469
|
-
const { ...nativeTokenRequest } = nativeRequest;
|
|
13470
|
-
// fall back to native calls
|
|
13471
|
-
const messageBody = {
|
|
13472
|
-
method: NativeExtensionMethod.GetToken,
|
|
13473
|
-
request: nativeTokenRequest,
|
|
13474
|
-
};
|
|
13475
|
-
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
13476
|
-
const validatedResponse = this.validateNativeResponse(response);
|
|
13477
|
-
return await this.handleNativeResponse(validatedResponse, nativeRequest, reqTimestamp)
|
|
13478
|
-
.then((result) => {
|
|
13479
|
-
nativeATMeasurement.end({
|
|
13480
|
-
success: true,
|
|
13481
|
-
isNativeBroker: true,
|
|
13482
|
-
requestId: result.requestId,
|
|
13483
|
-
});
|
|
13484
|
-
serverTelemetryManager.clearNativeBrokerErrorCode();
|
|
13485
|
-
return result;
|
|
13486
|
-
})
|
|
13487
|
-
.catch((error) => {
|
|
13488
|
-
nativeATMeasurement.end({
|
|
13395
|
+
window.postMessage(req, window.origin, [this.messageChannel.port2]);
|
|
13396
|
+
return new Promise((resolve, reject) => {
|
|
13397
|
+
this.handshakeResolvers.set(req.responseId, { resolve, reject });
|
|
13398
|
+
this.timeoutId = window.setTimeout(() => {
|
|
13399
|
+
/*
|
|
13400
|
+
* Throw an error if neither HandshakeResponse nor original Handshake request are received in a reasonable timeframe.
|
|
13401
|
+
* This typically suggests an event handler stopped propagation of the Handshake request but did not respond to it on the MessageChannel port
|
|
13402
|
+
*/
|
|
13403
|
+
window.removeEventListener("message", this.windowListener, false);
|
|
13404
|
+
this.messageChannel.port1.close();
|
|
13405
|
+
this.messageChannel.port2.close();
|
|
13406
|
+
this.handshakeEvent.end({
|
|
13407
|
+
extensionHandshakeTimedOut: true,
|
|
13489
13408
|
success: false,
|
|
13490
|
-
errorCode: error.errorCode,
|
|
13491
|
-
subErrorCode: error.subError,
|
|
13492
|
-
isNativeBroker: true,
|
|
13493
13409
|
});
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
if (e instanceof NativeAuthError) {
|
|
13499
|
-
serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode);
|
|
13500
|
-
}
|
|
13501
|
-
throw e;
|
|
13502
|
-
}
|
|
13503
|
-
}
|
|
13504
|
-
/**
|
|
13505
|
-
* Creates silent flow request
|
|
13506
|
-
* @param request
|
|
13507
|
-
* @param cachedAccount
|
|
13508
|
-
* @returns CommonSilentFlowRequest
|
|
13509
|
-
*/
|
|
13510
|
-
createSilentCacheRequest(request, cachedAccount) {
|
|
13511
|
-
return {
|
|
13512
|
-
authority: request.authority,
|
|
13513
|
-
correlationId: this.correlationId,
|
|
13514
|
-
scopes: ScopeSet.fromString(request.scope).asArray(),
|
|
13515
|
-
account: cachedAccount,
|
|
13516
|
-
forceRefresh: false,
|
|
13517
|
-
};
|
|
13410
|
+
reject(createBrowserAuthError(nativeHandshakeTimeout));
|
|
13411
|
+
this.handshakeResolvers.delete(req.responseId);
|
|
13412
|
+
}, this.handshakeTimeoutMs); // Use a reasonable timeout in milliseconds here
|
|
13413
|
+
});
|
|
13518
13414
|
}
|
|
13519
13415
|
/**
|
|
13520
|
-
*
|
|
13521
|
-
* @param
|
|
13522
|
-
* @param request
|
|
13523
|
-
* @returns authenticationResult
|
|
13416
|
+
* Invoked when a message is posted to the window. If a handshake request is received it means the extension is not installed.
|
|
13417
|
+
* @param event
|
|
13524
13418
|
*/
|
|
13525
|
-
|
|
13526
|
-
|
|
13527
|
-
|
|
13528
|
-
|
|
13419
|
+
onWindowMessage(event) {
|
|
13420
|
+
this.logger.trace("NativeMessageHandler - onWindowMessage called");
|
|
13421
|
+
// We only accept messages from ourselves
|
|
13422
|
+
if (event.source !== window) {
|
|
13423
|
+
return;
|
|
13529
13424
|
}
|
|
13530
|
-
|
|
13531
|
-
|
|
13532
|
-
|
|
13533
|
-
|
|
13534
|
-
if (!account) {
|
|
13535
|
-
throw createClientAuthError(noAccountFound);
|
|
13425
|
+
const request = event.data;
|
|
13426
|
+
if (!request.channel ||
|
|
13427
|
+
request.channel !== NativeConstants.CHANNEL_ID) {
|
|
13428
|
+
return;
|
|
13536
13429
|
}
|
|
13537
|
-
|
|
13538
|
-
|
|
13539
|
-
const silentRequest = this.createSilentCacheRequest(request, account);
|
|
13540
|
-
const result = await this.silentCacheClient.acquireToken(silentRequest);
|
|
13541
|
-
const fullAccount = {
|
|
13542
|
-
...account,
|
|
13543
|
-
idTokenClaims: result?.idTokenClaims,
|
|
13544
|
-
idToken: result?.idToken,
|
|
13545
|
-
};
|
|
13546
|
-
return {
|
|
13547
|
-
...result,
|
|
13548
|
-
account: fullAccount,
|
|
13549
|
-
};
|
|
13430
|
+
if (request.extensionId && request.extensionId !== this.extensionId) {
|
|
13431
|
+
return;
|
|
13550
13432
|
}
|
|
13551
|
-
|
|
13552
|
-
|
|
13433
|
+
if (request.body.method === NativeExtensionMethod.HandshakeRequest) {
|
|
13434
|
+
const handshakeResolver = this.handshakeResolvers.get(request.responseId);
|
|
13435
|
+
/*
|
|
13436
|
+
* Filter out responses with no matched resolvers sooner to keep channel ports open while waiting for
|
|
13437
|
+
* the proper response.
|
|
13438
|
+
*/
|
|
13439
|
+
if (!handshakeResolver) {
|
|
13440
|
+
this.logger.trace(`NativeMessageHandler.onWindowMessage - resolver can't be found for request ${request.responseId}`);
|
|
13441
|
+
return;
|
|
13442
|
+
}
|
|
13443
|
+
// If we receive this message back it means no extension intercepted the request, meaning no extension supporting handshake protocol is installed
|
|
13444
|
+
this.logger.verbose(request.extensionId
|
|
13445
|
+
? `Extension with id: ${request.extensionId} not installed`
|
|
13446
|
+
: "No extension installed");
|
|
13447
|
+
clearTimeout(this.timeoutId);
|
|
13448
|
+
this.messageChannel.port1.close();
|
|
13449
|
+
this.messageChannel.port2.close();
|
|
13450
|
+
window.removeEventListener("message", this.windowListener, false);
|
|
13451
|
+
this.handshakeEvent.end({
|
|
13452
|
+
success: false,
|
|
13453
|
+
extensionInstalled: false,
|
|
13454
|
+
});
|
|
13455
|
+
handshakeResolver.reject(createBrowserAuthError(nativeExtensionNotInstalled));
|
|
13553
13456
|
}
|
|
13554
13457
|
}
|
|
13555
13458
|
/**
|
|
13556
|
-
*
|
|
13557
|
-
* @param
|
|
13558
|
-
* @param {InProgressPerformanceEvent} rootMeasurement
|
|
13459
|
+
* Invoked when a message is received from the extension on the MessageChannel port
|
|
13460
|
+
* @param event
|
|
13559
13461
|
*/
|
|
13560
|
-
|
|
13561
|
-
this.logger.trace("
|
|
13562
|
-
const
|
|
13563
|
-
|
|
13564
|
-
const
|
|
13565
|
-
const messageBody = {
|
|
13566
|
-
method: NativeExtensionMethod.GetToken,
|
|
13567
|
-
request: nativeRequest,
|
|
13568
|
-
};
|
|
13462
|
+
onChannelMessage(event) {
|
|
13463
|
+
this.logger.trace("NativeMessageHandler - onChannelMessage called.");
|
|
13464
|
+
const request = event.data;
|
|
13465
|
+
const resolver = this.resolvers.get(request.responseId);
|
|
13466
|
+
const handshakeResolver = this.handshakeResolvers.get(request.responseId);
|
|
13569
13467
|
try {
|
|
13570
|
-
const
|
|
13571
|
-
|
|
13572
|
-
|
|
13573
|
-
|
|
13574
|
-
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
if (
|
|
13579
|
-
|
|
13468
|
+
const method = request.body.method;
|
|
13469
|
+
if (method === NativeExtensionMethod.Response) {
|
|
13470
|
+
if (!resolver) {
|
|
13471
|
+
return;
|
|
13472
|
+
}
|
|
13473
|
+
const response = request.body.response;
|
|
13474
|
+
this.logger.trace("NativeMessageHandler - Received response from browser extension");
|
|
13475
|
+
this.logger.tracePii(`NativeMessageHandler - Received response from browser extension: ${JSON.stringify(response)}`);
|
|
13476
|
+
if (response.status !== "Success") {
|
|
13477
|
+
resolver.reject(createNativeAuthError(response.code, response.description, response.ext));
|
|
13478
|
+
}
|
|
13479
|
+
else if (response.result) {
|
|
13480
|
+
if (response.result["code"] &&
|
|
13481
|
+
response.result["description"]) {
|
|
13482
|
+
resolver.reject(createNativeAuthError(response.result["code"], response.result["description"], response.result["ext"]));
|
|
13483
|
+
}
|
|
13484
|
+
else {
|
|
13485
|
+
resolver.resolve(response.result);
|
|
13486
|
+
}
|
|
13487
|
+
}
|
|
13488
|
+
else {
|
|
13489
|
+
throw createAuthError(unexpectedError, "Event does not contain result.");
|
|
13580
13490
|
}
|
|
13491
|
+
this.resolvers.delete(request.responseId);
|
|
13492
|
+
}
|
|
13493
|
+
else if (method === NativeExtensionMethod.HandshakeResponse) {
|
|
13494
|
+
if (!handshakeResolver) {
|
|
13495
|
+
this.logger.trace(`NativeMessageHandler.onChannelMessage - resolver can't be found for request ${request.responseId}`);
|
|
13496
|
+
return;
|
|
13497
|
+
}
|
|
13498
|
+
clearTimeout(this.timeoutId); // Clear setTimeout
|
|
13499
|
+
window.removeEventListener("message", this.windowListener, false); // Remove 'No extension' listener
|
|
13500
|
+
this.extensionId = request.extensionId;
|
|
13501
|
+
this.extensionVersion = request.body.version;
|
|
13502
|
+
this.logger.verbose(`NativeMessageHandler - Received HandshakeResponse from extension: ${this.extensionId}`);
|
|
13503
|
+
this.handshakeEvent.end({
|
|
13504
|
+
extensionInstalled: true,
|
|
13505
|
+
success: true,
|
|
13506
|
+
});
|
|
13507
|
+
handshakeResolver.resolve();
|
|
13508
|
+
this.handshakeResolvers.delete(request.responseId);
|
|
13509
|
+
}
|
|
13510
|
+
// Do nothing if method is not Response or HandshakeResponse
|
|
13511
|
+
}
|
|
13512
|
+
catch (err) {
|
|
13513
|
+
this.logger.error("Error parsing response from WAM Extension");
|
|
13514
|
+
this.logger.errorPii(`Error parsing response from WAM Extension: ${err}`);
|
|
13515
|
+
this.logger.errorPii(`Unable to parse ${event}`);
|
|
13516
|
+
if (resolver) {
|
|
13517
|
+
resolver.reject(err);
|
|
13518
|
+
}
|
|
13519
|
+
else if (handshakeResolver) {
|
|
13520
|
+
handshakeResolver.reject(err);
|
|
13581
13521
|
}
|
|
13582
13522
|
}
|
|
13583
|
-
this.browserStorage.setTemporaryCache(TemporaryCacheKeys.NATIVE_REQUEST, JSON.stringify(nativeRequest), true);
|
|
13584
|
-
const navigationOptions = {
|
|
13585
|
-
apiId: ApiId.acquireTokenRedirect,
|
|
13586
|
-
timeout: this.config.system.redirectNavigationTimeout,
|
|
13587
|
-
noHistory: false,
|
|
13588
|
-
};
|
|
13589
|
-
const redirectUri = this.config.auth.navigateToLoginRequestUrl
|
|
13590
|
-
? window.location.href
|
|
13591
|
-
: this.getRedirectUri(request.redirectUri);
|
|
13592
|
-
rootMeasurement.end({ success: true });
|
|
13593
|
-
await this.navigationClient.navigateExternal(redirectUri, navigationOptions); // Need to treat this as external to ensure handleRedirectPromise is run again
|
|
13594
13523
|
}
|
|
13595
13524
|
/**
|
|
13596
|
-
*
|
|
13597
|
-
* @
|
|
13598
|
-
* @param correlationId {string?} correlation identifier
|
|
13525
|
+
* Returns the Id for the browser extension this handler is communicating with
|
|
13526
|
+
* @returns
|
|
13599
13527
|
*/
|
|
13600
|
-
|
|
13601
|
-
this.
|
|
13602
|
-
if (!this.browserStorage.isInteractionInProgress(true)) {
|
|
13603
|
-
this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
|
|
13604
|
-
return null;
|
|
13605
|
-
}
|
|
13606
|
-
// remove prompt from the request to prevent WAM from prompting twice
|
|
13607
|
-
const cachedRequest = this.browserStorage.getCachedNativeRequest();
|
|
13608
|
-
if (!cachedRequest) {
|
|
13609
|
-
this.logger.verbose("NativeInteractionClient - handleRedirectPromise called but there is no cached request, returning null.");
|
|
13610
|
-
if (performanceClient && correlationId) {
|
|
13611
|
-
performanceClient?.addFields({ errorCode: "no_cached_request" }, correlationId);
|
|
13612
|
-
}
|
|
13613
|
-
return null;
|
|
13614
|
-
}
|
|
13615
|
-
const { prompt, ...request } = cachedRequest;
|
|
13616
|
-
if (prompt) {
|
|
13617
|
-
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.");
|
|
13618
|
-
}
|
|
13619
|
-
this.browserStorage.removeItem(this.browserStorage.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST));
|
|
13620
|
-
const messageBody = {
|
|
13621
|
-
method: NativeExtensionMethod.GetToken,
|
|
13622
|
-
request: request,
|
|
13623
|
-
};
|
|
13624
|
-
const reqTimestamp = nowSeconds();
|
|
13625
|
-
try {
|
|
13626
|
-
this.logger.verbose("NativeInteractionClient - handleRedirectPromise sending message to native broker.");
|
|
13627
|
-
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
13628
|
-
this.validateNativeResponse(response);
|
|
13629
|
-
const result = this.handleNativeResponse(response, request, reqTimestamp);
|
|
13630
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
13631
|
-
const res = await result;
|
|
13632
|
-
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
13633
|
-
serverTelemetryManager.clearNativeBrokerErrorCode();
|
|
13634
|
-
return res;
|
|
13635
|
-
}
|
|
13636
|
-
catch (e) {
|
|
13637
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
13638
|
-
throw e;
|
|
13639
|
-
}
|
|
13528
|
+
getExtensionId() {
|
|
13529
|
+
return this.extensionId;
|
|
13640
13530
|
}
|
|
13641
13531
|
/**
|
|
13642
|
-
*
|
|
13643
|
-
* @
|
|
13532
|
+
* Returns the version for the browser extension this handler is communicating with
|
|
13533
|
+
* @returns
|
|
13644
13534
|
*/
|
|
13645
|
-
|
|
13646
|
-
this.
|
|
13647
|
-
return Promise.reject("Logout not implemented yet");
|
|
13535
|
+
getExtensionVersion() {
|
|
13536
|
+
return this.extensionVersion;
|
|
13648
13537
|
}
|
|
13649
13538
|
/**
|
|
13650
|
-
*
|
|
13651
|
-
* @param
|
|
13652
|
-
* @param
|
|
13653
|
-
* @param
|
|
13539
|
+
* Returns boolean indicating whether or not the request should attempt to use native broker
|
|
13540
|
+
* @param logger
|
|
13541
|
+
* @param config
|
|
13542
|
+
* @param nativeExtensionProvider
|
|
13543
|
+
* @param authenticationScheme
|
|
13654
13544
|
*/
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
|
|
13658
|
-
|
|
13659
|
-
|
|
13660
|
-
|
|
13661
|
-
nativeAccountId: request.accountId,
|
|
13662
|
-
})?.homeAccountId;
|
|
13663
|
-
// add exception for double brokering, please note this is temporary and will be fortified in future
|
|
13664
|
-
if (request.extraParameters?.child_client_id &&
|
|
13665
|
-
response.account.id !== request.accountId) {
|
|
13666
|
-
this.logger.info("handleNativeServerResponse: Double broker flow detected, ignoring accountId mismatch");
|
|
13545
|
+
static isPlatformBrokerAvailable(config, logger, nativeExtensionProvider, authenticationScheme) {
|
|
13546
|
+
logger.trace("isPlatformBrokerAvailable called");
|
|
13547
|
+
if (!config.system.allowPlatformBroker) {
|
|
13548
|
+
logger.trace("isPlatformBrokerAvailable: allowPlatformBroker is not enabled, returning false");
|
|
13549
|
+
// Developer disabled WAM
|
|
13550
|
+
return false;
|
|
13667
13551
|
}
|
|
13668
|
-
|
|
13669
|
-
|
|
13670
|
-
//
|
|
13671
|
-
|
|
13552
|
+
if (!nativeExtensionProvider) {
|
|
13553
|
+
logger.trace("isPlatformBrokerAvailable: Platform extension provider is not initialized, returning false");
|
|
13554
|
+
// Extension is not available
|
|
13555
|
+
return false;
|
|
13672
13556
|
}
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
await this.cacheAccount(baseAccount);
|
|
13686
|
-
await this.cacheNativeTokens(response, request, homeAccountIdentifier, idTokenClaims, response.access_token, result.tenantId, reqTimestamp);
|
|
13687
|
-
return result;
|
|
13557
|
+
if (authenticationScheme) {
|
|
13558
|
+
switch (authenticationScheme) {
|
|
13559
|
+
case AuthenticationScheme.BEARER:
|
|
13560
|
+
case AuthenticationScheme.POP:
|
|
13561
|
+
logger.trace("isPlatformBrokerAvailable: authenticationScheme is supported, returning true");
|
|
13562
|
+
return true;
|
|
13563
|
+
default:
|
|
13564
|
+
logger.trace("isPlatformBrokerAvailable: authenticationScheme is not supported, returning false");
|
|
13565
|
+
return false;
|
|
13566
|
+
}
|
|
13567
|
+
}
|
|
13568
|
+
return true;
|
|
13688
13569
|
}
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13570
|
+
}
|
|
13571
|
+
|
|
13572
|
+
/*
|
|
13573
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13574
|
+
* Licensed under the MIT License.
|
|
13575
|
+
*/
|
|
13576
|
+
/**
|
|
13577
|
+
* Extracts the BrowserStateObject from the state string.
|
|
13578
|
+
* @param browserCrypto
|
|
13579
|
+
* @param state
|
|
13580
|
+
*/
|
|
13581
|
+
function extractBrowserRequestState(browserCrypto, state) {
|
|
13582
|
+
if (!state) {
|
|
13583
|
+
return null;
|
|
13699
13584
|
}
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13705
|
-
|
|
13706
|
-
|
|
13707
|
-
|
|
13708
|
-
|
|
13709
|
-
|
|
13585
|
+
try {
|
|
13586
|
+
const requestStateObj = ProtocolUtils.parseRequestState(browserCrypto, state);
|
|
13587
|
+
return requestStateObj.libraryState.meta;
|
|
13588
|
+
}
|
|
13589
|
+
catch (e) {
|
|
13590
|
+
throw createClientAuthError(invalidState);
|
|
13591
|
+
}
|
|
13592
|
+
}
|
|
13593
|
+
|
|
13594
|
+
/*
|
|
13595
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13596
|
+
* Licensed under the MIT License.
|
|
13597
|
+
*/
|
|
13598
|
+
function deserializeResponse(responseString, responseLocation, logger) {
|
|
13599
|
+
// Deserialize hash fragment response parameters.
|
|
13600
|
+
const serverParams = getDeserializedResponse(responseString);
|
|
13601
|
+
if (!serverParams) {
|
|
13602
|
+
if (!stripLeadingHashOrQuery(responseString)) {
|
|
13603
|
+
// Hash or Query string is empty
|
|
13604
|
+
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.`);
|
|
13605
|
+
throw createBrowserAuthError(hashEmptyError);
|
|
13606
|
+
}
|
|
13607
|
+
else {
|
|
13608
|
+
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.`);
|
|
13609
|
+
logger.errorPii(`The ${responseLocation} detected is: ${responseString}`);
|
|
13610
|
+
throw createBrowserAuthError(hashDoesNotContainKnownProperties);
|
|
13611
|
+
}
|
|
13612
|
+
}
|
|
13613
|
+
return serverParams;
|
|
13614
|
+
}
|
|
13615
|
+
/**
|
|
13616
|
+
* Returns the interaction type that the response object belongs to
|
|
13617
|
+
*/
|
|
13618
|
+
function validateInteractionType(response, browserCrypto, interactionType) {
|
|
13619
|
+
if (!response.state) {
|
|
13620
|
+
throw createBrowserAuthError(noStateInHash);
|
|
13621
|
+
}
|
|
13622
|
+
const platformStateObj = extractBrowserRequestState(browserCrypto, response.state);
|
|
13623
|
+
if (!platformStateObj) {
|
|
13624
|
+
throw createBrowserAuthError(unableToParseState);
|
|
13625
|
+
}
|
|
13626
|
+
if (platformStateObj.interactionType !== interactionType) {
|
|
13627
|
+
throw createBrowserAuthError(stateInteractionTypeMismatch);
|
|
13628
|
+
}
|
|
13629
|
+
}
|
|
13630
|
+
|
|
13631
|
+
/*
|
|
13632
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13633
|
+
* Licensed under the MIT License.
|
|
13634
|
+
*/
|
|
13635
|
+
/**
|
|
13636
|
+
* Abstract class which defines operations for a browser interaction handling class.
|
|
13637
|
+
*/
|
|
13638
|
+
class InteractionHandler {
|
|
13639
|
+
constructor(authCodeModule, storageImpl, authCodeRequest, logger, performanceClient) {
|
|
13640
|
+
this.authModule = authCodeModule;
|
|
13641
|
+
this.browserStorage = storageImpl;
|
|
13642
|
+
this.authCodeRequest = authCodeRequest;
|
|
13643
|
+
this.logger = logger;
|
|
13644
|
+
this.performanceClient = performanceClient;
|
|
13710
13645
|
}
|
|
13711
13646
|
/**
|
|
13712
|
-
*
|
|
13713
|
-
* @param
|
|
13714
|
-
* @param response
|
|
13647
|
+
* Function to handle response parameters from hash.
|
|
13648
|
+
* @param locationHash
|
|
13715
13649
|
*/
|
|
13716
|
-
async
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13723
|
-
|
|
13724
|
-
|
|
13725
|
-
|
|
13726
|
-
|
|
13650
|
+
async handleCodeResponse(response, request) {
|
|
13651
|
+
this.performanceClient.addQueueMeasurement(PerformanceEvents.HandleCodeResponse, request.correlationId);
|
|
13652
|
+
let authCodeResponse;
|
|
13653
|
+
try {
|
|
13654
|
+
authCodeResponse = getAuthorizationCodePayload(response, request.state);
|
|
13655
|
+
}
|
|
13656
|
+
catch (e) {
|
|
13657
|
+
if (e instanceof ServerError &&
|
|
13658
|
+
e.subError === userCancelled) {
|
|
13659
|
+
// Translate server error caused by user closing native prompt to corresponding first class MSAL error
|
|
13660
|
+
throw createBrowserAuthError(userCancelled);
|
|
13727
13661
|
}
|
|
13728
|
-
|
|
13729
|
-
|
|
13730
|
-
const shrParameters = {
|
|
13731
|
-
resourceRequestMethod: request.resourceRequestMethod,
|
|
13732
|
-
resourceRequestUri: request.resourceRequestUri,
|
|
13733
|
-
shrClaims: request.shrClaims,
|
|
13734
|
-
shrNonce: request.shrNonce,
|
|
13735
|
-
};
|
|
13736
|
-
/**
|
|
13737
|
-
* KeyID must be present in the native request from when the PoP key was generated in order for
|
|
13738
|
-
* PopTokenGenerator to query the full key for signing
|
|
13739
|
-
*/
|
|
13740
|
-
if (!request.keyId) {
|
|
13741
|
-
throw createClientAuthError(keyIdMissing);
|
|
13662
|
+
else {
|
|
13663
|
+
throw e;
|
|
13742
13664
|
}
|
|
13743
|
-
|
|
13665
|
+
}
|
|
13666
|
+
return invokeAsync(this.handleCodeResponseFromServer.bind(this), PerformanceEvents.HandleCodeResponseFromServer, this.logger, this.performanceClient, request.correlationId)(authCodeResponse, request);
|
|
13667
|
+
}
|
|
13668
|
+
/**
|
|
13669
|
+
* Process auth code response from AAD
|
|
13670
|
+
* @param authCodeResponse
|
|
13671
|
+
* @param state
|
|
13672
|
+
* @param authority
|
|
13673
|
+
* @param networkModule
|
|
13674
|
+
* @returns
|
|
13675
|
+
*/
|
|
13676
|
+
async handleCodeResponseFromServer(authCodeResponse, request, validateNonce = true) {
|
|
13677
|
+
this.performanceClient.addQueueMeasurement(PerformanceEvents.HandleCodeResponseFromServer, request.correlationId);
|
|
13678
|
+
this.logger.trace("InteractionHandler.handleCodeResponseFromServer called");
|
|
13679
|
+
// Assign code to request
|
|
13680
|
+
this.authCodeRequest.code = authCodeResponse.code;
|
|
13681
|
+
// Check for new cloud instance
|
|
13682
|
+
if (authCodeResponse.cloud_instance_host_name) {
|
|
13683
|
+
await invokeAsync(this.authModule.updateAuthority.bind(this.authModule), PerformanceEvents.UpdateTokenEndpointAuthority, this.logger, this.performanceClient, request.correlationId)(authCodeResponse.cloud_instance_host_name, request.correlationId);
|
|
13684
|
+
}
|
|
13685
|
+
// Nonce validation not needed when redirect not involved (e.g. hybrid spa, renewing token via rt)
|
|
13686
|
+
if (validateNonce) {
|
|
13687
|
+
// TODO: Assigning "response nonce" to "request nonce" is confusing. Refactor the function doing validation to accept request nonce directly
|
|
13688
|
+
authCodeResponse.nonce = request.nonce || undefined;
|
|
13689
|
+
}
|
|
13690
|
+
authCodeResponse.state = request.state;
|
|
13691
|
+
// Add CCS parameters if available
|
|
13692
|
+
if (authCodeResponse.client_info) {
|
|
13693
|
+
this.authCodeRequest.clientInfo = authCodeResponse.client_info;
|
|
13744
13694
|
}
|
|
13745
13695
|
else {
|
|
13746
|
-
|
|
13696
|
+
const ccsCred = this.createCcsCredentials(request);
|
|
13697
|
+
if (ccsCred) {
|
|
13698
|
+
this.authCodeRequest.ccsCredential = ccsCred;
|
|
13699
|
+
}
|
|
13747
13700
|
}
|
|
13701
|
+
// Acquire token with retrieved code.
|
|
13702
|
+
const tokenResponse = (await invokeAsync(this.authModule.acquireToken.bind(this.authModule), PerformanceEvents.AuthClientAcquireToken, this.logger, this.performanceClient, request.correlationId)(this.authCodeRequest, authCodeResponse));
|
|
13703
|
+
return tokenResponse;
|
|
13748
13704
|
}
|
|
13749
13705
|
/**
|
|
13750
|
-
*
|
|
13751
|
-
* @param response
|
|
13752
|
-
* @param request
|
|
13753
|
-
* @param idTokenObj
|
|
13754
|
-
* @param accountEntity
|
|
13755
|
-
* @param authority
|
|
13756
|
-
* @param reqTimestamp
|
|
13757
|
-
* @returns
|
|
13706
|
+
* Build ccs creds if available
|
|
13758
13707
|
*/
|
|
13759
|
-
|
|
13760
|
-
|
|
13761
|
-
|
|
13762
|
-
|
|
13763
|
-
|
|
13764
|
-
|
|
13765
|
-
: ScopeSet.fromString(request.scope);
|
|
13766
|
-
const accountProperties = response.account.properties || {};
|
|
13767
|
-
const uid = accountProperties["UID"] ||
|
|
13768
|
-
idTokenClaims.oid ||
|
|
13769
|
-
idTokenClaims.sub ||
|
|
13770
|
-
Constants.EMPTY_STRING;
|
|
13771
|
-
const tid = accountProperties["TenantId"] ||
|
|
13772
|
-
idTokenClaims.tid ||
|
|
13773
|
-
Constants.EMPTY_STRING;
|
|
13774
|
-
const accountInfo = updateAccountTenantProfileData(accountEntity.getAccountInfo(), undefined, // tenantProfile optional
|
|
13775
|
-
idTokenClaims, response.id_token);
|
|
13776
|
-
/**
|
|
13777
|
-
* In pairwise broker flows, this check prevents the broker's native account id
|
|
13778
|
-
* from being returned over the embedded app's account id.
|
|
13779
|
-
*/
|
|
13780
|
-
if (accountInfo.nativeAccountId !== response.account.id) {
|
|
13781
|
-
accountInfo.nativeAccountId = response.account.id;
|
|
13708
|
+
createCcsCredentials(request) {
|
|
13709
|
+
if (request.account) {
|
|
13710
|
+
return {
|
|
13711
|
+
credential: request.account.homeAccountId,
|
|
13712
|
+
type: CcsCredentialType.HOME_ACCOUNT_ID,
|
|
13713
|
+
};
|
|
13782
13714
|
}
|
|
13783
|
-
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
|
|
13788
|
-
|
|
13789
|
-
|
|
13790
|
-
uniqueId: uid,
|
|
13791
|
-
tenantId: tid,
|
|
13792
|
-
scopes: responseScopes.asArray(),
|
|
13793
|
-
account: accountInfo,
|
|
13794
|
-
idToken: response.id_token,
|
|
13795
|
-
idTokenClaims: idTokenClaims,
|
|
13796
|
-
accessToken: responseAccessToken,
|
|
13797
|
-
fromCache: mats ? this.isResponseFromCache(mats) : false,
|
|
13798
|
-
// Request timestamp and NativeResponse expires_in are in seconds, converting to Date for AuthenticationResult
|
|
13799
|
-
expiresOn: toDateFromSeconds(reqTimestamp + response.expires_in),
|
|
13800
|
-
tokenType: tokenType,
|
|
13801
|
-
correlationId: this.correlationId,
|
|
13802
|
-
state: response.state,
|
|
13803
|
-
fromNativeBroker: true,
|
|
13804
|
-
};
|
|
13805
|
-
return result;
|
|
13715
|
+
else if (request.loginHint) {
|
|
13716
|
+
return {
|
|
13717
|
+
credential: request.loginHint,
|
|
13718
|
+
type: CcsCredentialType.UPN,
|
|
13719
|
+
};
|
|
13720
|
+
}
|
|
13721
|
+
return null;
|
|
13806
13722
|
}
|
|
13723
|
+
}
|
|
13724
|
+
|
|
13725
|
+
/*
|
|
13726
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13727
|
+
* Licensed under the MIT License.
|
|
13728
|
+
*/
|
|
13729
|
+
class SilentCacheClient extends StandardInteractionClient {
|
|
13807
13730
|
/**
|
|
13808
|
-
*
|
|
13809
|
-
* @param
|
|
13731
|
+
* Returns unexpired tokens from the cache, if available
|
|
13732
|
+
* @param silentRequest
|
|
13810
13733
|
*/
|
|
13811
|
-
async
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
13815
|
-
this.
|
|
13816
|
-
|
|
13734
|
+
async acquireToken(silentRequest) {
|
|
13735
|
+
this.performanceClient.addQueueMeasurement(PerformanceEvents.SilentCacheClientAcquireToken, silentRequest.correlationId);
|
|
13736
|
+
// Telemetry manager only used to increment cacheHits here
|
|
13737
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenSilent_silentFlow);
|
|
13738
|
+
const clientConfig = await invokeAsync(this.getClientConfiguration.bind(this), PerformanceEvents.StandardInteractionClientGetClientConfiguration, this.logger, this.performanceClient, this.correlationId)({
|
|
13739
|
+
serverTelemetryManager,
|
|
13740
|
+
requestAuthority: silentRequest.authority,
|
|
13741
|
+
requestAzureCloudOptions: silentRequest.azureCloudOptions,
|
|
13742
|
+
account: silentRequest.account,
|
|
13817
13743
|
});
|
|
13744
|
+
const silentAuthClient = new SilentFlowClient(clientConfig, this.performanceClient);
|
|
13745
|
+
this.logger.verbose("Silent auth client created");
|
|
13746
|
+
try {
|
|
13747
|
+
const response = await invokeAsync(silentAuthClient.acquireCachedToken.bind(silentAuthClient), PerformanceEvents.SilentFlowClientAcquireCachedToken, this.logger, this.performanceClient, silentRequest.correlationId)(silentRequest);
|
|
13748
|
+
const authResponse = response[0];
|
|
13749
|
+
this.performanceClient.addFields({
|
|
13750
|
+
fromCache: true,
|
|
13751
|
+
}, silentRequest.correlationId);
|
|
13752
|
+
return authResponse;
|
|
13753
|
+
}
|
|
13754
|
+
catch (error) {
|
|
13755
|
+
if (error instanceof BrowserAuthError &&
|
|
13756
|
+
error.errorCode === cryptoKeyNotFound) {
|
|
13757
|
+
this.logger.verbose("Signing keypair for bound access token not found. Refreshing bound access token and generating a new crypto keypair.");
|
|
13758
|
+
}
|
|
13759
|
+
throw error;
|
|
13760
|
+
}
|
|
13818
13761
|
}
|
|
13819
13762
|
/**
|
|
13820
|
-
*
|
|
13821
|
-
* @param
|
|
13822
|
-
* @param request
|
|
13823
|
-
* @param homeAccountIdentifier
|
|
13824
|
-
* @param idTokenObj
|
|
13825
|
-
* @param responseAccessToken
|
|
13826
|
-
* @param tenantId
|
|
13827
|
-
* @param reqTimestamp
|
|
13763
|
+
* API to silenty clear the browser cache.
|
|
13764
|
+
* @param logoutRequest
|
|
13828
13765
|
*/
|
|
13829
|
-
|
|
13830
|
-
|
|
13831
|
-
|
|
13832
|
-
|
|
13833
|
-
? Constants.SHR_NONCE_VALIDITY
|
|
13834
|
-
: (typeof response.expires_in === "string"
|
|
13835
|
-
? parseInt(response.expires_in, 10)
|
|
13836
|
-
: response.expires_in) || 0;
|
|
13837
|
-
const tokenExpirationSeconds = reqTimestamp + expiresIn;
|
|
13838
|
-
const responseScopes = this.generateScopes(response, request);
|
|
13839
|
-
const cachedAccessToken = createAccessTokenEntity(homeAccountIdentifier, request.authority, responseAccessToken, request.clientId, idTokenClaims.tid || tenantId, responseScopes.printScopes(), tokenExpirationSeconds, 0, base64Decode, undefined, request.tokenType, undefined, request.keyId);
|
|
13840
|
-
const nativeCacheRecord = {
|
|
13841
|
-
idToken: cachedIdToken,
|
|
13842
|
-
accessToken: cachedAccessToken,
|
|
13843
|
-
};
|
|
13844
|
-
return this.nativeStorageManager.saveCacheRecord(nativeCacheRecord, this.correlationId, request.storeInCache);
|
|
13766
|
+
logout(logoutRequest) {
|
|
13767
|
+
this.logger.verbose("logoutRedirect called");
|
|
13768
|
+
const validLogoutRequest = this.initializeLogoutRequest(logoutRequest);
|
|
13769
|
+
return this.clearCacheOnLogout(validLogoutRequest?.account);
|
|
13845
13770
|
}
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13852
|
-
|
|
13771
|
+
}
|
|
13772
|
+
|
|
13773
|
+
/*
|
|
13774
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13775
|
+
* Licensed under the MIT License.
|
|
13776
|
+
*/
|
|
13777
|
+
class NativeInteractionClient extends BaseInteractionClient {
|
|
13778
|
+
constructor(config, browserStorage, browserCrypto, logger, eventHandler, navigationClient, apiId, performanceClient, provider, accountId, nativeStorageImpl, correlationId) {
|
|
13779
|
+
super(config, browserStorage, browserCrypto, logger, eventHandler, navigationClient, performanceClient, provider, correlationId);
|
|
13780
|
+
this.apiId = apiId;
|
|
13781
|
+
this.accountId = accountId;
|
|
13782
|
+
this.nativeMessageHandler = provider;
|
|
13783
|
+
this.nativeStorageManager = nativeStorageImpl;
|
|
13784
|
+
this.silentCacheClient = new SilentCacheClient(config, this.nativeStorageManager, browserCrypto, logger, eventHandler, navigationClient, performanceClient, provider, correlationId);
|
|
13785
|
+
const extensionName = this.nativeMessageHandler.getExtensionId() ===
|
|
13786
|
+
NativeConstants.PREFERRED_EXTENSION_ID
|
|
13787
|
+
? "chrome"
|
|
13788
|
+
: this.nativeMessageHandler.getExtensionId()?.length
|
|
13789
|
+
? "unknown"
|
|
13790
|
+
: undefined;
|
|
13791
|
+
this.skus = ServerTelemetryManager.makeExtraSkuString({
|
|
13792
|
+
libraryName: BrowserConstants.MSAL_SKU,
|
|
13793
|
+
libraryVersion: version,
|
|
13794
|
+
extensionName: extensionName,
|
|
13853
13795
|
extensionVersion: this.nativeMessageHandler.getExtensionVersion(),
|
|
13854
|
-
|
|
13855
|
-
matsAccountJoinOnStart: mats.account_join_on_start,
|
|
13856
|
-
matsAccountJoinOnEnd: mats.account_join_on_end,
|
|
13857
|
-
matsDeviceJoin: mats.device_join,
|
|
13858
|
-
matsPromptBehavior: mats.prompt_behavior,
|
|
13859
|
-
matsApiErrorCode: mats.api_error_code,
|
|
13860
|
-
matsUiVisible: mats.ui_visible,
|
|
13861
|
-
matsSilentCode: mats.silent_code,
|
|
13862
|
-
matsSilentBiSubCode: mats.silent_bi_sub_code,
|
|
13863
|
-
matsSilentMessage: mats.silent_message,
|
|
13864
|
-
matsSilentStatus: mats.silent_status,
|
|
13865
|
-
matsHttpStatus: mats.http_status,
|
|
13866
|
-
matsHttpEventCount: mats.http_event_count,
|
|
13867
|
-
}, this.correlationId);
|
|
13868
|
-
return mats;
|
|
13796
|
+
});
|
|
13869
13797
|
}
|
|
13870
13798
|
/**
|
|
13871
|
-
*
|
|
13872
|
-
* @param
|
|
13799
|
+
* Adds SKUs to request extra query parameters
|
|
13800
|
+
* @param request {NativeTokenRequest}
|
|
13801
|
+
* @private
|
|
13873
13802
|
*/
|
|
13874
|
-
|
|
13875
|
-
|
|
13876
|
-
|
|
13877
|
-
|
|
13878
|
-
|
|
13879
|
-
response.hasOwnProperty("scope") &&
|
|
13880
|
-
response.hasOwnProperty("expires_in")) {
|
|
13881
|
-
return response;
|
|
13882
|
-
}
|
|
13883
|
-
else {
|
|
13884
|
-
throw createAuthError(unexpectedError, "Response missing expected properties.");
|
|
13885
|
-
}
|
|
13803
|
+
addRequestSKUs(request) {
|
|
13804
|
+
request.extraParameters = {
|
|
13805
|
+
...request.extraParameters,
|
|
13806
|
+
[X_CLIENT_EXTRA_SKU]: this.skus,
|
|
13807
|
+
};
|
|
13886
13808
|
}
|
|
13887
13809
|
/**
|
|
13888
|
-
*
|
|
13889
|
-
* @param
|
|
13890
|
-
* @returns
|
|
13810
|
+
* Acquire token from native platform via browser extension
|
|
13811
|
+
* @param request
|
|
13891
13812
|
*/
|
|
13892
|
-
|
|
13893
|
-
|
|
13813
|
+
async acquireToken(request, cacheLookupPolicy) {
|
|
13814
|
+
this.performanceClient.addQueueMeasurement(PerformanceEvents.NativeInteractionClientAcquireToken, request.correlationId);
|
|
13815
|
+
this.logger.trace("NativeInteractionClient - acquireToken called.");
|
|
13816
|
+
// start the perf measurement
|
|
13817
|
+
const nativeATMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.NativeInteractionClientAcquireToken, request.correlationId);
|
|
13818
|
+
const reqTimestamp = nowSeconds();
|
|
13819
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
13820
|
+
try {
|
|
13821
|
+
// initialize native request
|
|
13822
|
+
const nativeRequest = await this.initializeNativeRequest(request);
|
|
13823
|
+
// check if the tokens can be retrieved from internal cache
|
|
13894
13824
|
try {
|
|
13895
|
-
|
|
13825
|
+
const result = await this.acquireTokensFromCache(this.accountId, nativeRequest);
|
|
13826
|
+
nativeATMeasurement.end({
|
|
13827
|
+
success: true,
|
|
13828
|
+
isNativeBroker: false,
|
|
13829
|
+
fromCache: true,
|
|
13830
|
+
});
|
|
13831
|
+
return result;
|
|
13896
13832
|
}
|
|
13897
13833
|
catch (e) {
|
|
13898
|
-
|
|
13834
|
+
if (cacheLookupPolicy === CacheLookupPolicy.AccessToken) {
|
|
13835
|
+
this.logger.info("MSAL internal Cache does not contain tokens, return error as per cache policy");
|
|
13836
|
+
throw e;
|
|
13837
|
+
}
|
|
13838
|
+
// continue with a native call for any and all errors
|
|
13839
|
+
this.logger.info("MSAL internal Cache does not contain tokens, proceed to make a native call");
|
|
13899
13840
|
}
|
|
13841
|
+
const { ...nativeTokenRequest } = nativeRequest;
|
|
13842
|
+
// fall back to native calls
|
|
13843
|
+
const messageBody = {
|
|
13844
|
+
method: NativeExtensionMethod.GetToken,
|
|
13845
|
+
request: nativeTokenRequest,
|
|
13846
|
+
};
|
|
13847
|
+
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
13848
|
+
const validatedResponse = this.validateNativeResponse(response);
|
|
13849
|
+
return await this.handleNativeResponse(validatedResponse, nativeRequest, reqTimestamp)
|
|
13850
|
+
.then((result) => {
|
|
13851
|
+
nativeATMeasurement.end({
|
|
13852
|
+
success: true,
|
|
13853
|
+
isNativeBroker: true,
|
|
13854
|
+
requestId: result.requestId,
|
|
13855
|
+
});
|
|
13856
|
+
serverTelemetryManager.clearNativeBrokerErrorCode();
|
|
13857
|
+
return result;
|
|
13858
|
+
})
|
|
13859
|
+
.catch((error) => {
|
|
13860
|
+
nativeATMeasurement.end({
|
|
13861
|
+
success: false,
|
|
13862
|
+
errorCode: error.errorCode,
|
|
13863
|
+
subErrorCode: error.subError,
|
|
13864
|
+
isNativeBroker: true,
|
|
13865
|
+
});
|
|
13866
|
+
throw error;
|
|
13867
|
+
});
|
|
13900
13868
|
}
|
|
13901
|
-
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
|
|
13906
|
-
* @returns
|
|
13907
|
-
*/
|
|
13908
|
-
isResponseFromCache(mats) {
|
|
13909
|
-
if (typeof mats.is_cached === "undefined") {
|
|
13910
|
-
this.logger.verbose("NativeInteractionClient - MATS telemetry does not contain field indicating if response was served from cache. Returning false.");
|
|
13911
|
-
return false;
|
|
13869
|
+
catch (e) {
|
|
13870
|
+
if (e instanceof NativeAuthError) {
|
|
13871
|
+
serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode);
|
|
13872
|
+
}
|
|
13873
|
+
throw e;
|
|
13912
13874
|
}
|
|
13913
|
-
return !!mats.is_cached;
|
|
13914
13875
|
}
|
|
13915
13876
|
/**
|
|
13916
|
-
*
|
|
13877
|
+
* Creates silent flow request
|
|
13917
13878
|
* @param request
|
|
13879
|
+
* @param cachedAccount
|
|
13880
|
+
* @returns CommonSilentFlowRequest
|
|
13918
13881
|
*/
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
if (request.account) {
|
|
13923
|
-
// validate authority
|
|
13924
|
-
await this.getDiscoveredAuthority({
|
|
13925
|
-
requestAuthority,
|
|
13926
|
-
requestAzureCloudOptions: request.azureCloudOptions,
|
|
13927
|
-
account: request.account,
|
|
13928
|
-
});
|
|
13929
|
-
}
|
|
13930
|
-
const canonicalAuthority = new UrlString(requestAuthority);
|
|
13931
|
-
canonicalAuthority.validateAsUri();
|
|
13932
|
-
// 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.
|
|
13933
|
-
const { scopes, ...remainingProperties } = request;
|
|
13934
|
-
const scopeSet = new ScopeSet(scopes || []);
|
|
13935
|
-
scopeSet.appendScopes(OIDC_DEFAULT_SCOPES);
|
|
13936
|
-
const getPrompt = () => {
|
|
13937
|
-
// If request is silent, prompt is always none
|
|
13938
|
-
switch (this.apiId) {
|
|
13939
|
-
case ApiId.ssoSilent:
|
|
13940
|
-
case ApiId.acquireTokenSilent_silentFlow:
|
|
13941
|
-
this.logger.trace("initializeNativeRequest: silent request sets prompt to none");
|
|
13942
|
-
return PromptValue.NONE;
|
|
13943
|
-
}
|
|
13944
|
-
// Prompt not provided, request may proceed and native broker decides if it needs to prompt
|
|
13945
|
-
if (!request.prompt) {
|
|
13946
|
-
this.logger.trace("initializeNativeRequest: prompt was not provided");
|
|
13947
|
-
return undefined;
|
|
13948
|
-
}
|
|
13949
|
-
// If request is interactive, check if prompt provided is allowed to go directly to native broker
|
|
13950
|
-
switch (request.prompt) {
|
|
13951
|
-
case PromptValue.NONE:
|
|
13952
|
-
case PromptValue.CONSENT:
|
|
13953
|
-
case PromptValue.LOGIN:
|
|
13954
|
-
this.logger.trace("initializeNativeRequest: prompt is compatible with native flow");
|
|
13955
|
-
return request.prompt;
|
|
13956
|
-
default:
|
|
13957
|
-
this.logger.trace(`initializeNativeRequest: prompt = ${request.prompt} is not compatible with native flow`);
|
|
13958
|
-
throw createBrowserAuthError(nativePromptNotSupported);
|
|
13959
|
-
}
|
|
13960
|
-
};
|
|
13961
|
-
const validatedRequest = {
|
|
13962
|
-
...remainingProperties,
|
|
13963
|
-
accountId: this.accountId,
|
|
13964
|
-
clientId: this.config.auth.clientId,
|
|
13965
|
-
authority: canonicalAuthority.urlString,
|
|
13966
|
-
scope: scopeSet.printScopes(),
|
|
13967
|
-
redirectUri: this.getRedirectUri(request.redirectUri),
|
|
13968
|
-
prompt: getPrompt(),
|
|
13882
|
+
createSilentCacheRequest(request, cachedAccount) {
|
|
13883
|
+
return {
|
|
13884
|
+
authority: request.authority,
|
|
13969
13885
|
correlationId: this.correlationId,
|
|
13970
|
-
|
|
13971
|
-
|
|
13972
|
-
|
|
13973
|
-
...request.extraQueryParameters,
|
|
13974
|
-
...request.tokenQueryParameters,
|
|
13975
|
-
},
|
|
13976
|
-
extendedExpiryToken: false,
|
|
13977
|
-
keyId: request.popKid,
|
|
13886
|
+
scopes: ScopeSet.fromString(request.scope).asArray(),
|
|
13887
|
+
account: cachedAccount,
|
|
13888
|
+
forceRefresh: false,
|
|
13978
13889
|
};
|
|
13979
|
-
// Check for PoP token requests: signPopToken should only be set to true if popKid is not set
|
|
13980
|
-
if (validatedRequest.signPopToken && !!request.popKid) {
|
|
13981
|
-
throw createBrowserAuthError(invalidPopTokenRequest);
|
|
13982
|
-
}
|
|
13983
|
-
this.handleExtraBrokerParams(validatedRequest);
|
|
13984
|
-
validatedRequest.extraParameters =
|
|
13985
|
-
validatedRequest.extraParameters || {};
|
|
13986
|
-
validatedRequest.extraParameters.telemetry =
|
|
13987
|
-
NativeConstants.MATS_TELEMETRY;
|
|
13988
|
-
if (request.authenticationScheme === AuthenticationScheme.POP) {
|
|
13989
|
-
// add POP request type
|
|
13990
|
-
const shrParameters = {
|
|
13991
|
-
resourceRequestUri: request.resourceRequestUri,
|
|
13992
|
-
resourceRequestMethod: request.resourceRequestMethod,
|
|
13993
|
-
shrClaims: request.shrClaims,
|
|
13994
|
-
shrNonce: request.shrNonce,
|
|
13995
|
-
};
|
|
13996
|
-
const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);
|
|
13997
|
-
// generate reqCnf if not provided in the request
|
|
13998
|
-
let reqCnfData;
|
|
13999
|
-
if (!validatedRequest.keyId) {
|
|
14000
|
-
const generatedReqCnfData = await invokeAsync(popTokenGenerator.generateCnf.bind(popTokenGenerator), PerformanceEvents.PopTokenGenerateCnf, this.logger, this.performanceClient, request.correlationId)(shrParameters, this.logger);
|
|
14001
|
-
reqCnfData = generatedReqCnfData.reqCnfString;
|
|
14002
|
-
validatedRequest.keyId = generatedReqCnfData.kid;
|
|
14003
|
-
validatedRequest.signPopToken = true;
|
|
14004
|
-
}
|
|
14005
|
-
else {
|
|
14006
|
-
reqCnfData = this.browserCrypto.base64UrlEncode(JSON.stringify({ kid: validatedRequest.keyId }));
|
|
14007
|
-
validatedRequest.signPopToken = false;
|
|
14008
|
-
}
|
|
14009
|
-
// SPAs require whole string to be passed to broker
|
|
14010
|
-
validatedRequest.reqCnf = reqCnfData;
|
|
14011
|
-
}
|
|
14012
|
-
this.addRequestSKUs(validatedRequest);
|
|
14013
|
-
return validatedRequest;
|
|
14014
13890
|
}
|
|
14015
13891
|
/**
|
|
14016
|
-
*
|
|
14017
|
-
* @param
|
|
14018
|
-
* @
|
|
13892
|
+
* Fetches the tokens from the cache if un-expired
|
|
13893
|
+
* @param nativeAccountId
|
|
13894
|
+
* @param request
|
|
13895
|
+
* @returns authenticationResult
|
|
14019
13896
|
*/
|
|
14020
|
-
|
|
14021
|
-
|
|
14022
|
-
|
|
14023
|
-
|
|
14024
|
-
request.extraParameters.hasOwnProperty(CLIENT_ID);
|
|
14025
|
-
if (!request.embeddedClientId && !hasExtraBrokerParams) {
|
|
14026
|
-
return;
|
|
13897
|
+
async acquireTokensFromCache(nativeAccountId, request) {
|
|
13898
|
+
if (!nativeAccountId) {
|
|
13899
|
+
this.logger.warning("NativeInteractionClient:acquireTokensFromCache - No nativeAccountId provided");
|
|
13900
|
+
throw createClientAuthError(noAccountFound);
|
|
14027
13901
|
}
|
|
14028
|
-
|
|
14029
|
-
const
|
|
14030
|
-
|
|
14031
|
-
|
|
14032
|
-
|
|
13902
|
+
// fetch the account from browser cache
|
|
13903
|
+
const account = this.browserStorage.getBaseAccountInfo({
|
|
13904
|
+
nativeAccountId,
|
|
13905
|
+
});
|
|
13906
|
+
if (!account) {
|
|
13907
|
+
throw createClientAuthError(noAccountFound);
|
|
14033
13908
|
}
|
|
14034
|
-
|
|
14035
|
-
|
|
14036
|
-
|
|
14037
|
-
|
|
14038
|
-
|
|
13909
|
+
// leverage silent flow for cached tokens retrieval
|
|
13910
|
+
try {
|
|
13911
|
+
const silentRequest = this.createSilentCacheRequest(request, account);
|
|
13912
|
+
const result = await this.silentCacheClient.acquireToken(silentRequest);
|
|
13913
|
+
const fullAccount = {
|
|
13914
|
+
...account,
|
|
13915
|
+
idTokenClaims: result?.idTokenClaims,
|
|
13916
|
+
idToken: result?.idToken,
|
|
13917
|
+
};
|
|
13918
|
+
return {
|
|
13919
|
+
...result,
|
|
13920
|
+
account: fullAccount,
|
|
13921
|
+
};
|
|
13922
|
+
}
|
|
13923
|
+
catch (e) {
|
|
13924
|
+
throw e;
|
|
14039
13925
|
}
|
|
14040
|
-
request.extraParameters = {
|
|
14041
|
-
child_client_id,
|
|
14042
|
-
child_redirect_uri,
|
|
14043
|
-
};
|
|
14044
|
-
this.performanceClient?.addFields({
|
|
14045
|
-
embeddedClientId: child_client_id,
|
|
14046
|
-
embeddedRedirectUri: child_redirect_uri,
|
|
14047
|
-
}, request.correlationId);
|
|
14048
|
-
}
|
|
14049
|
-
}
|
|
14050
|
-
|
|
14051
|
-
/*
|
|
14052
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
14053
|
-
* Licensed under the MIT License.
|
|
14054
|
-
*/
|
|
14055
|
-
class NativeMessageHandler {
|
|
14056
|
-
constructor(logger, handshakeTimeoutMs, performanceClient, extensionId) {
|
|
14057
|
-
this.logger = logger;
|
|
14058
|
-
this.handshakeTimeoutMs = handshakeTimeoutMs;
|
|
14059
|
-
this.extensionId = extensionId;
|
|
14060
|
-
this.resolvers = new Map(); // Used for non-handshake messages
|
|
14061
|
-
this.handshakeResolvers = new Map(); // Used for handshake messages
|
|
14062
|
-
this.messageChannel = new MessageChannel();
|
|
14063
|
-
this.windowListener = this.onWindowMessage.bind(this); // Window event callback doesn't have access to 'this' unless it's bound
|
|
14064
|
-
this.performanceClient = performanceClient;
|
|
14065
|
-
this.handshakeEvent = performanceClient.startMeasurement(PerformanceEvents.NativeMessageHandlerHandshake);
|
|
14066
13926
|
}
|
|
14067
13927
|
/**
|
|
14068
|
-
*
|
|
14069
|
-
* @param
|
|
13928
|
+
* Acquires a token from native platform then redirects to the redirectUri instead of returning the response
|
|
13929
|
+
* @param {RedirectRequest} request
|
|
13930
|
+
* @param {InProgressPerformanceEvent} rootMeasurement
|
|
14070
13931
|
*/
|
|
14071
|
-
async
|
|
14072
|
-
this.logger.trace("
|
|
14073
|
-
const
|
|
14074
|
-
|
|
14075
|
-
|
|
14076
|
-
|
|
14077
|
-
|
|
13932
|
+
async acquireTokenRedirect(request, rootMeasurement) {
|
|
13933
|
+
this.logger.trace("NativeInteractionClient - acquireTokenRedirect called.");
|
|
13934
|
+
const { ...remainingParameters } = request;
|
|
13935
|
+
delete remainingParameters.onRedirectNavigate;
|
|
13936
|
+
const nativeRequest = await this.initializeNativeRequest(remainingParameters);
|
|
13937
|
+
const messageBody = {
|
|
13938
|
+
method: NativeExtensionMethod.GetToken,
|
|
13939
|
+
request: nativeRequest,
|
|
14078
13940
|
};
|
|
14079
|
-
|
|
14080
|
-
|
|
14081
|
-
|
|
14082
|
-
|
|
14083
|
-
|
|
14084
|
-
|
|
13941
|
+
try {
|
|
13942
|
+
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
13943
|
+
this.validateNativeResponse(response);
|
|
13944
|
+
}
|
|
13945
|
+
catch (e) {
|
|
13946
|
+
// Only throw fatal errors here to allow application to fallback to regular redirect. Otherwise proceed and the error will be thrown in handleRedirectPromise
|
|
13947
|
+
if (e instanceof NativeAuthError) {
|
|
13948
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
13949
|
+
serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode);
|
|
13950
|
+
if (isFatalNativeAuthError(e)) {
|
|
13951
|
+
throw e;
|
|
13952
|
+
}
|
|
13953
|
+
}
|
|
13954
|
+
}
|
|
13955
|
+
this.browserStorage.setTemporaryCache(TemporaryCacheKeys.NATIVE_REQUEST, JSON.stringify(nativeRequest), true);
|
|
13956
|
+
const navigationOptions = {
|
|
13957
|
+
apiId: ApiId.acquireTokenRedirect,
|
|
13958
|
+
timeout: this.config.system.redirectNavigationTimeout,
|
|
13959
|
+
noHistory: false,
|
|
13960
|
+
};
|
|
13961
|
+
const redirectUri = this.config.auth.navigateToLoginRequestUrl
|
|
13962
|
+
? window.location.href
|
|
13963
|
+
: this.getRedirectUri(request.redirectUri);
|
|
13964
|
+
rootMeasurement.end({ success: true });
|
|
13965
|
+
await this.navigationClient.navigateExternal(redirectUri, navigationOptions); // Need to treat this as external to ensure handleRedirectPromise is run again
|
|
14085
13966
|
}
|
|
14086
13967
|
/**
|
|
14087
|
-
*
|
|
14088
|
-
* @param {
|
|
14089
|
-
* @param {
|
|
14090
|
-
* @param {IPerformanceClient} performanceClient
|
|
14091
|
-
* @param {ICrypto} crypto
|
|
13968
|
+
* If the previous page called native platform for a token using redirect APIs, send the same request again and return the response
|
|
13969
|
+
* @param performanceClient {IPerformanceClient?}
|
|
13970
|
+
* @param correlationId {string?} correlation identifier
|
|
14092
13971
|
*/
|
|
14093
|
-
|
|
14094
|
-
logger.trace("
|
|
13972
|
+
async handleRedirectPromise(performanceClient, correlationId) {
|
|
13973
|
+
this.logger.trace("NativeInteractionClient - handleRedirectPromise called.");
|
|
13974
|
+
if (!this.browserStorage.isInteractionInProgress(true)) {
|
|
13975
|
+
this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
|
|
13976
|
+
return null;
|
|
13977
|
+
}
|
|
13978
|
+
// remove prompt from the request to prevent WAM from prompting twice
|
|
13979
|
+
const cachedRequest = this.browserStorage.getCachedNativeRequest();
|
|
13980
|
+
if (!cachedRequest) {
|
|
13981
|
+
this.logger.verbose("NativeInteractionClient - handleRedirectPromise called but there is no cached request, returning null.");
|
|
13982
|
+
if (performanceClient && correlationId) {
|
|
13983
|
+
performanceClient?.addFields({ errorCode: "no_cached_request" }, correlationId);
|
|
13984
|
+
}
|
|
13985
|
+
return null;
|
|
13986
|
+
}
|
|
13987
|
+
const { prompt, ...request } = cachedRequest;
|
|
13988
|
+
if (prompt) {
|
|
13989
|
+
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.");
|
|
13990
|
+
}
|
|
13991
|
+
this.browserStorage.removeItem(this.browserStorage.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST));
|
|
13992
|
+
const messageBody = {
|
|
13993
|
+
method: NativeExtensionMethod.GetToken,
|
|
13994
|
+
request: request,
|
|
13995
|
+
};
|
|
13996
|
+
const reqTimestamp = nowSeconds();
|
|
14095
13997
|
try {
|
|
14096
|
-
|
|
14097
|
-
await
|
|
14098
|
-
|
|
13998
|
+
this.logger.verbose("NativeInteractionClient - handleRedirectPromise sending message to native broker.");
|
|
13999
|
+
const response = await this.nativeMessageHandler.sendMessage(messageBody);
|
|
14000
|
+
this.validateNativeResponse(response);
|
|
14001
|
+
const result = this.handleNativeResponse(response, request, reqTimestamp);
|
|
14002
|
+
const res = await result;
|
|
14003
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
14004
|
+
serverTelemetryManager.clearNativeBrokerErrorCode();
|
|
14005
|
+
return res;
|
|
14099
14006
|
}
|
|
14100
14007
|
catch (e) {
|
|
14101
|
-
|
|
14102
|
-
const backupProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient);
|
|
14103
|
-
await backupProvider.sendHandshakeRequest();
|
|
14104
|
-
return backupProvider;
|
|
14008
|
+
throw e;
|
|
14105
14009
|
}
|
|
14106
14010
|
}
|
|
14107
14011
|
/**
|
|
14108
|
-
*
|
|
14012
|
+
* Logout from native platform via browser extension
|
|
14013
|
+
* @param request
|
|
14109
14014
|
*/
|
|
14110
|
-
|
|
14111
|
-
this.logger.trace("
|
|
14112
|
-
|
|
14113
|
-
window.addEventListener("message", this.windowListener, false); // false is important, because content script message processing should work first
|
|
14114
|
-
const req = {
|
|
14115
|
-
channel: NativeConstants.CHANNEL_ID,
|
|
14116
|
-
extensionId: this.extensionId,
|
|
14117
|
-
responseId: createNewGuid(),
|
|
14118
|
-
body: {
|
|
14119
|
-
method: NativeExtensionMethod.HandshakeRequest,
|
|
14120
|
-
},
|
|
14121
|
-
};
|
|
14122
|
-
this.handshakeEvent.add({
|
|
14123
|
-
extensionId: this.extensionId,
|
|
14124
|
-
extensionHandshakeTimeoutMs: this.handshakeTimeoutMs,
|
|
14125
|
-
});
|
|
14126
|
-
this.messageChannel.port1.onmessage = (event) => {
|
|
14127
|
-
this.onChannelMessage(event);
|
|
14128
|
-
};
|
|
14129
|
-
window.postMessage(req, window.origin, [this.messageChannel.port2]);
|
|
14130
|
-
return new Promise((resolve, reject) => {
|
|
14131
|
-
this.handshakeResolvers.set(req.responseId, { resolve, reject });
|
|
14132
|
-
this.timeoutId = window.setTimeout(() => {
|
|
14133
|
-
/*
|
|
14134
|
-
* Throw an error if neither HandshakeResponse nor original Handshake request are received in a reasonable timeframe.
|
|
14135
|
-
* This typically suggests an event handler stopped propagation of the Handshake request but did not respond to it on the MessageChannel port
|
|
14136
|
-
*/
|
|
14137
|
-
window.removeEventListener("message", this.windowListener, false);
|
|
14138
|
-
this.messageChannel.port1.close();
|
|
14139
|
-
this.messageChannel.port2.close();
|
|
14140
|
-
this.handshakeEvent.end({
|
|
14141
|
-
extensionHandshakeTimedOut: true,
|
|
14142
|
-
success: false,
|
|
14143
|
-
});
|
|
14144
|
-
reject(createBrowserAuthError(nativeHandshakeTimeout));
|
|
14145
|
-
this.handshakeResolvers.delete(req.responseId);
|
|
14146
|
-
}, this.handshakeTimeoutMs); // Use a reasonable timeout in milliseconds here
|
|
14147
|
-
});
|
|
14015
|
+
logout() {
|
|
14016
|
+
this.logger.trace("NativeInteractionClient - logout called.");
|
|
14017
|
+
return Promise.reject("Logout not implemented yet");
|
|
14148
14018
|
}
|
|
14149
14019
|
/**
|
|
14150
|
-
*
|
|
14151
|
-
* @param
|
|
14020
|
+
* Transform response from native platform into AuthenticationResult object which will be returned to the end user
|
|
14021
|
+
* @param response
|
|
14022
|
+
* @param request
|
|
14023
|
+
* @param reqTimestamp
|
|
14152
14024
|
*/
|
|
14153
|
-
|
|
14154
|
-
this.logger.trace("
|
|
14155
|
-
//
|
|
14156
|
-
|
|
14157
|
-
|
|
14158
|
-
|
|
14159
|
-
|
|
14160
|
-
|
|
14161
|
-
|
|
14162
|
-
|
|
14163
|
-
|
|
14164
|
-
|
|
14165
|
-
return;
|
|
14025
|
+
async handleNativeResponse(response, request, reqTimestamp) {
|
|
14026
|
+
this.logger.trace("NativeInteractionClient - handleNativeResponse called.");
|
|
14027
|
+
// generate identifiers
|
|
14028
|
+
const idTokenClaims = extractTokenClaims(response.id_token, base64Decode);
|
|
14029
|
+
const homeAccountIdentifier = this.createHomeAccountIdentifier(response, idTokenClaims);
|
|
14030
|
+
const cachedhomeAccountId = this.browserStorage.getAccountInfoFilteredBy({
|
|
14031
|
+
nativeAccountId: request.accountId,
|
|
14032
|
+
})?.homeAccountId;
|
|
14033
|
+
// add exception for double brokering, please note this is temporary and will be fortified in future
|
|
14034
|
+
if (request.extraParameters?.child_client_id &&
|
|
14035
|
+
response.account.id !== request.accountId) {
|
|
14036
|
+
this.logger.info("handleNativeServerResponse: Double broker flow detected, ignoring accountId mismatch");
|
|
14166
14037
|
}
|
|
14167
|
-
if (
|
|
14168
|
-
|
|
14169
|
-
|
|
14170
|
-
|
|
14171
|
-
* the proper response.
|
|
14172
|
-
*/
|
|
14173
|
-
if (!handshakeResolver) {
|
|
14174
|
-
this.logger.trace(`NativeMessageHandler.onWindowMessage - resolver can't be found for request ${request.responseId}`);
|
|
14175
|
-
return;
|
|
14176
|
-
}
|
|
14177
|
-
// If we receive this message back it means no extension intercepted the request, meaning no extension supporting handshake protocol is installed
|
|
14178
|
-
this.logger.verbose(request.extensionId
|
|
14179
|
-
? `Extension with id: ${request.extensionId} not installed`
|
|
14180
|
-
: "No extension installed");
|
|
14181
|
-
clearTimeout(this.timeoutId);
|
|
14182
|
-
this.messageChannel.port1.close();
|
|
14183
|
-
this.messageChannel.port2.close();
|
|
14184
|
-
window.removeEventListener("message", this.windowListener, false);
|
|
14185
|
-
this.handshakeEvent.end({
|
|
14186
|
-
success: false,
|
|
14187
|
-
extensionInstalled: false,
|
|
14188
|
-
});
|
|
14189
|
-
handshakeResolver.reject(createBrowserAuthError(nativeExtensionNotInstalled));
|
|
14038
|
+
else if (homeAccountIdentifier !== cachedhomeAccountId &&
|
|
14039
|
+
response.account.id !== request.accountId) {
|
|
14040
|
+
// 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
|
|
14041
|
+
throw createNativeAuthError(userSwitch);
|
|
14190
14042
|
}
|
|
14043
|
+
// Get the preferred_cache domain for the given authority
|
|
14044
|
+
const authority = await this.getDiscoveredAuthority({
|
|
14045
|
+
requestAuthority: request.authority,
|
|
14046
|
+
});
|
|
14047
|
+
const baseAccount = buildAccountToCache(this.browserStorage, authority, homeAccountIdentifier, base64Decode, idTokenClaims, response.client_info, undefined, // environment
|
|
14048
|
+
idTokenClaims.tid, undefined, // auth code payload
|
|
14049
|
+
response.account.id, this.logger);
|
|
14050
|
+
// Ensure expires_in is in number format
|
|
14051
|
+
response.expires_in = Number(response.expires_in);
|
|
14052
|
+
// generate authenticationResult
|
|
14053
|
+
const result = await this.generateAuthenticationResult(response, request, idTokenClaims, baseAccount, authority.canonicalAuthority, reqTimestamp);
|
|
14054
|
+
// cache accounts and tokens in the appropriate storage
|
|
14055
|
+
await this.cacheAccount(baseAccount);
|
|
14056
|
+
await this.cacheNativeTokens(response, request, homeAccountIdentifier, idTokenClaims, response.access_token, result.tenantId, reqTimestamp);
|
|
14057
|
+
return result;
|
|
14191
14058
|
}
|
|
14192
14059
|
/**
|
|
14193
|
-
*
|
|
14194
|
-
* @param
|
|
14060
|
+
* creates an homeAccountIdentifier for the account
|
|
14061
|
+
* @param response
|
|
14062
|
+
* @param idTokenObj
|
|
14063
|
+
* @returns
|
|
14195
14064
|
*/
|
|
14196
|
-
|
|
14197
|
-
|
|
14198
|
-
const
|
|
14199
|
-
|
|
14200
|
-
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14204
|
-
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14065
|
+
createHomeAccountIdentifier(response, idTokenClaims) {
|
|
14066
|
+
// Save account in browser storage
|
|
14067
|
+
const homeAccountIdentifier = AccountEntity.generateHomeAccountId(response.client_info || Constants.EMPTY_STRING, AuthorityType.Default, this.logger, this.browserCrypto, idTokenClaims);
|
|
14068
|
+
return homeAccountIdentifier;
|
|
14069
|
+
}
|
|
14070
|
+
/**
|
|
14071
|
+
* Helper to generate scopes
|
|
14072
|
+
* @param response
|
|
14073
|
+
* @param request
|
|
14074
|
+
* @returns
|
|
14075
|
+
*/
|
|
14076
|
+
generateScopes(response, request) {
|
|
14077
|
+
return response.scope
|
|
14078
|
+
? ScopeSet.fromString(response.scope)
|
|
14079
|
+
: ScopeSet.fromString(request.scope);
|
|
14080
|
+
}
|
|
14081
|
+
/**
|
|
14082
|
+
* If PoP token is requesred, records the PoP token if returned from the WAM, else generates one in the browser
|
|
14083
|
+
* @param request
|
|
14084
|
+
* @param response
|
|
14085
|
+
*/
|
|
14086
|
+
async generatePopAccessToken(response, request) {
|
|
14087
|
+
if (request.tokenType === AuthenticationScheme.POP &&
|
|
14088
|
+
request.signPopToken) {
|
|
14089
|
+
/**
|
|
14090
|
+
* This code prioritizes SHR returned from the native layer. In case of error/SHR not calculated from WAM and the AT
|
|
14091
|
+
* is still received, SHR is calculated locally
|
|
14092
|
+
*/
|
|
14093
|
+
// Check if native layer returned an SHR token
|
|
14094
|
+
if (response.shr) {
|
|
14095
|
+
this.logger.trace("handleNativeServerResponse: SHR is enabled in native layer");
|
|
14096
|
+
return response.shr;
|
|
14226
14097
|
}
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
handshakeResolver.resolve();
|
|
14242
|
-
this.handshakeResolvers.delete(request.responseId);
|
|
14098
|
+
// Generate SHR in msal js if WAM does not compute it when POP is enabled
|
|
14099
|
+
const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);
|
|
14100
|
+
const shrParameters = {
|
|
14101
|
+
resourceRequestMethod: request.resourceRequestMethod,
|
|
14102
|
+
resourceRequestUri: request.resourceRequestUri,
|
|
14103
|
+
shrClaims: request.shrClaims,
|
|
14104
|
+
shrNonce: request.shrNonce,
|
|
14105
|
+
};
|
|
14106
|
+
/**
|
|
14107
|
+
* KeyID must be present in the native request from when the PoP key was generated in order for
|
|
14108
|
+
* PopTokenGenerator to query the full key for signing
|
|
14109
|
+
*/
|
|
14110
|
+
if (!request.keyId) {
|
|
14111
|
+
throw createClientAuthError(keyIdMissing);
|
|
14243
14112
|
}
|
|
14244
|
-
|
|
14113
|
+
return popTokenGenerator.signPopToken(response.access_token, request.keyId, shrParameters);
|
|
14245
14114
|
}
|
|
14246
|
-
|
|
14247
|
-
|
|
14248
|
-
this.logger.errorPii(`Error parsing response from WAM Extension: ${err}`);
|
|
14249
|
-
this.logger.errorPii(`Unable to parse ${event}`);
|
|
14250
|
-
if (resolver) {
|
|
14251
|
-
resolver.reject(err);
|
|
14252
|
-
}
|
|
14253
|
-
else if (handshakeResolver) {
|
|
14254
|
-
handshakeResolver.reject(err);
|
|
14255
|
-
}
|
|
14115
|
+
else {
|
|
14116
|
+
return response.access_token;
|
|
14256
14117
|
}
|
|
14257
14118
|
}
|
|
14258
14119
|
/**
|
|
14259
|
-
*
|
|
14120
|
+
* Generates authentication result
|
|
14121
|
+
* @param response
|
|
14122
|
+
* @param request
|
|
14123
|
+
* @param idTokenObj
|
|
14124
|
+
* @param accountEntity
|
|
14125
|
+
* @param authority
|
|
14126
|
+
* @param reqTimestamp
|
|
14260
14127
|
* @returns
|
|
14261
14128
|
*/
|
|
14262
|
-
|
|
14263
|
-
|
|
14129
|
+
async generateAuthenticationResult(response, request, idTokenClaims, accountEntity, authority, reqTimestamp) {
|
|
14130
|
+
// Add Native Broker fields to Telemetry
|
|
14131
|
+
const mats = this.addTelemetryFromNativeResponse(response);
|
|
14132
|
+
// If scopes not returned in server response, use request scopes
|
|
14133
|
+
const responseScopes = response.scope
|
|
14134
|
+
? ScopeSet.fromString(response.scope)
|
|
14135
|
+
: ScopeSet.fromString(request.scope);
|
|
14136
|
+
const accountProperties = response.account.properties || {};
|
|
14137
|
+
const uid = accountProperties["UID"] ||
|
|
14138
|
+
idTokenClaims.oid ||
|
|
14139
|
+
idTokenClaims.sub ||
|
|
14140
|
+
Constants.EMPTY_STRING;
|
|
14141
|
+
const tid = accountProperties["TenantId"] ||
|
|
14142
|
+
idTokenClaims.tid ||
|
|
14143
|
+
Constants.EMPTY_STRING;
|
|
14144
|
+
const accountInfo = updateAccountTenantProfileData(accountEntity.getAccountInfo(), undefined, // tenantProfile optional
|
|
14145
|
+
idTokenClaims, response.id_token);
|
|
14146
|
+
/**
|
|
14147
|
+
* In pairwise broker flows, this check prevents the broker's native account id
|
|
14148
|
+
* from being returned over the embedded app's account id.
|
|
14149
|
+
*/
|
|
14150
|
+
if (accountInfo.nativeAccountId !== response.account.id) {
|
|
14151
|
+
accountInfo.nativeAccountId = response.account.id;
|
|
14152
|
+
}
|
|
14153
|
+
// generate PoP token as needed
|
|
14154
|
+
const responseAccessToken = await this.generatePopAccessToken(response, request);
|
|
14155
|
+
const tokenType = request.tokenType === AuthenticationScheme.POP
|
|
14156
|
+
? AuthenticationScheme.POP
|
|
14157
|
+
: AuthenticationScheme.BEARER;
|
|
14158
|
+
const result = {
|
|
14159
|
+
authority: authority,
|
|
14160
|
+
uniqueId: uid,
|
|
14161
|
+
tenantId: tid,
|
|
14162
|
+
scopes: responseScopes.asArray(),
|
|
14163
|
+
account: accountInfo,
|
|
14164
|
+
idToken: response.id_token,
|
|
14165
|
+
idTokenClaims: idTokenClaims,
|
|
14166
|
+
accessToken: responseAccessToken,
|
|
14167
|
+
fromCache: mats ? this.isResponseFromCache(mats) : false,
|
|
14168
|
+
// Request timestamp and NativeResponse expires_in are in seconds, converting to Date for AuthenticationResult
|
|
14169
|
+
expiresOn: toDateFromSeconds(reqTimestamp + response.expires_in),
|
|
14170
|
+
tokenType: tokenType,
|
|
14171
|
+
correlationId: this.correlationId,
|
|
14172
|
+
state: response.state,
|
|
14173
|
+
fromNativeBroker: true,
|
|
14174
|
+
};
|
|
14175
|
+
return result;
|
|
14264
14176
|
}
|
|
14265
14177
|
/**
|
|
14266
|
-
*
|
|
14267
|
-
* @
|
|
14178
|
+
* cache the account entity in browser storage
|
|
14179
|
+
* @param accountEntity
|
|
14268
14180
|
*/
|
|
14269
|
-
|
|
14270
|
-
|
|
14181
|
+
async cacheAccount(accountEntity) {
|
|
14182
|
+
// Store the account info and hence `nativeAccountId` in browser cache
|
|
14183
|
+
await this.browserStorage.setAccount(accountEntity, this.correlationId);
|
|
14184
|
+
// Remove any existing cached tokens for this account in browser storage
|
|
14185
|
+
this.browserStorage.removeAccountContext(accountEntity).catch((e) => {
|
|
14186
|
+
this.logger.error(`Error occurred while removing account context from browser storage. ${e}`);
|
|
14187
|
+
});
|
|
14271
14188
|
}
|
|
14272
14189
|
/**
|
|
14273
|
-
*
|
|
14274
|
-
* @param
|
|
14275
|
-
* @param
|
|
14276
|
-
* @param
|
|
14277
|
-
* @param
|
|
14190
|
+
* Stores the access_token and id_token in inmemory storage
|
|
14191
|
+
* @param response
|
|
14192
|
+
* @param request
|
|
14193
|
+
* @param homeAccountIdentifier
|
|
14194
|
+
* @param idTokenObj
|
|
14195
|
+
* @param responseAccessToken
|
|
14196
|
+
* @param tenantId
|
|
14197
|
+
* @param reqTimestamp
|
|
14278
14198
|
*/
|
|
14279
|
-
|
|
14280
|
-
|
|
14281
|
-
|
|
14282
|
-
|
|
14283
|
-
|
|
14284
|
-
|
|
14199
|
+
cacheNativeTokens(response, request, homeAccountIdentifier, idTokenClaims, responseAccessToken, tenantId, reqTimestamp) {
|
|
14200
|
+
const cachedIdToken = createIdTokenEntity(homeAccountIdentifier, request.authority, response.id_token || "", request.clientId, idTokenClaims.tid || "");
|
|
14201
|
+
// cache accessToken in inmemory storage
|
|
14202
|
+
const expiresIn = request.tokenType === AuthenticationScheme.POP
|
|
14203
|
+
? Constants.SHR_NONCE_VALIDITY
|
|
14204
|
+
: (typeof response.expires_in === "string"
|
|
14205
|
+
? parseInt(response.expires_in, 10)
|
|
14206
|
+
: response.expires_in) || 0;
|
|
14207
|
+
const tokenExpirationSeconds = reqTimestamp + expiresIn;
|
|
14208
|
+
const responseScopes = this.generateScopes(response, request);
|
|
14209
|
+
const cachedAccessToken = createAccessTokenEntity(homeAccountIdentifier, request.authority, responseAccessToken, request.clientId, idTokenClaims.tid || tenantId, responseScopes.printScopes(), tokenExpirationSeconds, 0, base64Decode, undefined, request.tokenType, undefined, request.keyId);
|
|
14210
|
+
const nativeCacheRecord = {
|
|
14211
|
+
idToken: cachedIdToken,
|
|
14212
|
+
accessToken: cachedAccessToken,
|
|
14213
|
+
};
|
|
14214
|
+
return this.nativeStorageManager.saveCacheRecord(nativeCacheRecord, this.correlationId, request.storeInCache);
|
|
14215
|
+
}
|
|
14216
|
+
addTelemetryFromNativeResponse(response) {
|
|
14217
|
+
const mats = this.getMATSFromResponse(response);
|
|
14218
|
+
if (!mats) {
|
|
14219
|
+
return null;
|
|
14285
14220
|
}
|
|
14286
|
-
|
|
14287
|
-
|
|
14288
|
-
|
|
14289
|
-
|
|
14221
|
+
this.performanceClient.addFields({
|
|
14222
|
+
extensionId: this.nativeMessageHandler.getExtensionId(),
|
|
14223
|
+
extensionVersion: this.nativeMessageHandler.getExtensionVersion(),
|
|
14224
|
+
matsBrokerVersion: mats.broker_version,
|
|
14225
|
+
matsAccountJoinOnStart: mats.account_join_on_start,
|
|
14226
|
+
matsAccountJoinOnEnd: mats.account_join_on_end,
|
|
14227
|
+
matsDeviceJoin: mats.device_join,
|
|
14228
|
+
matsPromptBehavior: mats.prompt_behavior,
|
|
14229
|
+
matsApiErrorCode: mats.api_error_code,
|
|
14230
|
+
matsUiVisible: mats.ui_visible,
|
|
14231
|
+
matsSilentCode: mats.silent_code,
|
|
14232
|
+
matsSilentBiSubCode: mats.silent_bi_sub_code,
|
|
14233
|
+
matsSilentMessage: mats.silent_message,
|
|
14234
|
+
matsSilentStatus: mats.silent_status,
|
|
14235
|
+
matsHttpStatus: mats.http_status,
|
|
14236
|
+
matsHttpEventCount: mats.http_event_count,
|
|
14237
|
+
}, this.correlationId);
|
|
14238
|
+
return mats;
|
|
14239
|
+
}
|
|
14240
|
+
/**
|
|
14241
|
+
* Validates native platform response before processing
|
|
14242
|
+
* @param response
|
|
14243
|
+
*/
|
|
14244
|
+
validateNativeResponse(response) {
|
|
14245
|
+
if (response.hasOwnProperty("access_token") &&
|
|
14246
|
+
response.hasOwnProperty("id_token") &&
|
|
14247
|
+
response.hasOwnProperty("client_info") &&
|
|
14248
|
+
response.hasOwnProperty("account") &&
|
|
14249
|
+
response.hasOwnProperty("scope") &&
|
|
14250
|
+
response.hasOwnProperty("expires_in")) {
|
|
14251
|
+
return response;
|
|
14290
14252
|
}
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
case AuthenticationScheme.BEARER:
|
|
14294
|
-
case AuthenticationScheme.POP:
|
|
14295
|
-
logger.trace("isPlatformBrokerAvailable: authenticationScheme is supported, returning true");
|
|
14296
|
-
return true;
|
|
14297
|
-
default:
|
|
14298
|
-
logger.trace("isPlatformBrokerAvailable: authenticationScheme is not supported, returning false");
|
|
14299
|
-
return false;
|
|
14300
|
-
}
|
|
14253
|
+
else {
|
|
14254
|
+
throw createAuthError(unexpectedError, "Response missing expected properties.");
|
|
14301
14255
|
}
|
|
14302
|
-
return true;
|
|
14303
|
-
}
|
|
14304
|
-
}
|
|
14305
|
-
|
|
14306
|
-
/*
|
|
14307
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
14308
|
-
* Licensed under the MIT License.
|
|
14309
|
-
*/
|
|
14310
|
-
/**
|
|
14311
|
-
* Abstract class which defines operations for a browser interaction handling class.
|
|
14312
|
-
*/
|
|
14313
|
-
class InteractionHandler {
|
|
14314
|
-
constructor(authCodeModule, storageImpl, authCodeRequest, logger, performanceClient) {
|
|
14315
|
-
this.authModule = authCodeModule;
|
|
14316
|
-
this.browserStorage = storageImpl;
|
|
14317
|
-
this.authCodeRequest = authCodeRequest;
|
|
14318
|
-
this.logger = logger;
|
|
14319
|
-
this.performanceClient = performanceClient;
|
|
14320
14256
|
}
|
|
14321
14257
|
/**
|
|
14322
|
-
*
|
|
14323
|
-
* @param
|
|
14258
|
+
* Gets MATS telemetry from native response
|
|
14259
|
+
* @param response
|
|
14260
|
+
* @returns
|
|
14324
14261
|
*/
|
|
14325
|
-
|
|
14326
|
-
|
|
14327
|
-
|
|
14328
|
-
|
|
14329
|
-
authCodeResponse = getAuthorizationCodePayload(response, request.state);
|
|
14330
|
-
}
|
|
14331
|
-
catch (e) {
|
|
14332
|
-
if (e instanceof ServerError &&
|
|
14333
|
-
e.subError === userCancelled) {
|
|
14334
|
-
// Translate server error caused by user closing native prompt to corresponding first class MSAL error
|
|
14335
|
-
throw createBrowserAuthError(userCancelled);
|
|
14262
|
+
getMATSFromResponse(response) {
|
|
14263
|
+
if (response.properties.MATS) {
|
|
14264
|
+
try {
|
|
14265
|
+
return JSON.parse(response.properties.MATS);
|
|
14336
14266
|
}
|
|
14337
|
-
|
|
14338
|
-
|
|
14267
|
+
catch (e) {
|
|
14268
|
+
this.logger.error("NativeInteractionClient - Error parsing MATS telemetry, returning null instead");
|
|
14339
14269
|
}
|
|
14340
14270
|
}
|
|
14341
|
-
return
|
|
14271
|
+
return null;
|
|
14342
14272
|
}
|
|
14343
14273
|
/**
|
|
14344
|
-
*
|
|
14345
|
-
* @param
|
|
14346
|
-
* @param state
|
|
14347
|
-
* @param authority
|
|
14348
|
-
* @param networkModule
|
|
14274
|
+
* Returns whether or not response came from native cache
|
|
14275
|
+
* @param response
|
|
14349
14276
|
* @returns
|
|
14350
14277
|
*/
|
|
14351
|
-
|
|
14352
|
-
|
|
14353
|
-
|
|
14354
|
-
|
|
14355
|
-
this.authCodeRequest.code = authCodeResponse.code;
|
|
14356
|
-
// Check for new cloud instance
|
|
14357
|
-
if (authCodeResponse.cloud_instance_host_name) {
|
|
14358
|
-
await invokeAsync(this.authModule.updateAuthority.bind(this.authModule), PerformanceEvents.UpdateTokenEndpointAuthority, this.logger, this.performanceClient, request.correlationId)(authCodeResponse.cloud_instance_host_name, request.correlationId);
|
|
14359
|
-
}
|
|
14360
|
-
// Nonce validation not needed when redirect not involved (e.g. hybrid spa, renewing token via rt)
|
|
14361
|
-
if (validateNonce) {
|
|
14362
|
-
// TODO: Assigning "response nonce" to "request nonce" is confusing. Refactor the function doing validation to accept request nonce directly
|
|
14363
|
-
authCodeResponse.nonce = request.nonce || undefined;
|
|
14364
|
-
}
|
|
14365
|
-
authCodeResponse.state = request.state;
|
|
14366
|
-
// Add CCS parameters if available
|
|
14367
|
-
if (authCodeResponse.client_info) {
|
|
14368
|
-
this.authCodeRequest.clientInfo = authCodeResponse.client_info;
|
|
14369
|
-
}
|
|
14370
|
-
else {
|
|
14371
|
-
const ccsCred = this.createCcsCredentials(request);
|
|
14372
|
-
if (ccsCred) {
|
|
14373
|
-
this.authCodeRequest.ccsCredential = ccsCred;
|
|
14374
|
-
}
|
|
14278
|
+
isResponseFromCache(mats) {
|
|
14279
|
+
if (typeof mats.is_cached === "undefined") {
|
|
14280
|
+
this.logger.verbose("NativeInteractionClient - MATS telemetry does not contain field indicating if response was served from cache. Returning false.");
|
|
14281
|
+
return false;
|
|
14375
14282
|
}
|
|
14376
|
-
|
|
14377
|
-
const tokenResponse = (await invokeAsync(this.authModule.acquireToken.bind(this.authModule), PerformanceEvents.AuthClientAcquireToken, this.logger, this.performanceClient, request.correlationId)(this.authCodeRequest, authCodeResponse));
|
|
14378
|
-
return tokenResponse;
|
|
14283
|
+
return !!mats.is_cached;
|
|
14379
14284
|
}
|
|
14380
14285
|
/**
|
|
14381
|
-
*
|
|
14286
|
+
* Translates developer provided request object into NativeRequest object
|
|
14287
|
+
* @param request
|
|
14382
14288
|
*/
|
|
14383
|
-
|
|
14289
|
+
async initializeNativeRequest(request) {
|
|
14290
|
+
this.logger.trace("NativeInteractionClient - initializeNativeRequest called");
|
|
14291
|
+
const requestAuthority = request.authority || this.config.auth.authority;
|
|
14384
14292
|
if (request.account) {
|
|
14385
|
-
|
|
14386
|
-
|
|
14387
|
-
|
|
14388
|
-
|
|
14293
|
+
// validate authority
|
|
14294
|
+
await this.getDiscoveredAuthority({
|
|
14295
|
+
requestAuthority,
|
|
14296
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
14297
|
+
account: request.account,
|
|
14298
|
+
});
|
|
14389
14299
|
}
|
|
14390
|
-
|
|
14391
|
-
|
|
14392
|
-
|
|
14393
|
-
|
|
14300
|
+
const canonicalAuthority = new UrlString(requestAuthority);
|
|
14301
|
+
canonicalAuthority.validateAsUri();
|
|
14302
|
+
// 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.
|
|
14303
|
+
const { scopes, ...remainingProperties } = request;
|
|
14304
|
+
const scopeSet = new ScopeSet(scopes || []);
|
|
14305
|
+
scopeSet.appendScopes(OIDC_DEFAULT_SCOPES);
|
|
14306
|
+
const getPrompt = () => {
|
|
14307
|
+
// If request is silent, prompt is always none
|
|
14308
|
+
switch (this.apiId) {
|
|
14309
|
+
case ApiId.ssoSilent:
|
|
14310
|
+
case ApiId.acquireTokenSilent_silentFlow:
|
|
14311
|
+
this.logger.trace("initializeNativeRequest: silent request sets prompt to none");
|
|
14312
|
+
return PromptValue.NONE;
|
|
14313
|
+
}
|
|
14314
|
+
// Prompt not provided, request may proceed and native broker decides if it needs to prompt
|
|
14315
|
+
if (!request.prompt) {
|
|
14316
|
+
this.logger.trace("initializeNativeRequest: prompt was not provided");
|
|
14317
|
+
return undefined;
|
|
14318
|
+
}
|
|
14319
|
+
// If request is interactive, check if prompt provided is allowed to go directly to native broker
|
|
14320
|
+
switch (request.prompt) {
|
|
14321
|
+
case PromptValue.NONE:
|
|
14322
|
+
case PromptValue.CONSENT:
|
|
14323
|
+
case PromptValue.LOGIN:
|
|
14324
|
+
this.logger.trace("initializeNativeRequest: prompt is compatible with native flow");
|
|
14325
|
+
return request.prompt;
|
|
14326
|
+
default:
|
|
14327
|
+
this.logger.trace(`initializeNativeRequest: prompt = ${request.prompt} is not compatible with native flow`);
|
|
14328
|
+
throw createBrowserAuthError(nativePromptNotSupported);
|
|
14329
|
+
}
|
|
14330
|
+
};
|
|
14331
|
+
const validatedRequest = {
|
|
14332
|
+
...remainingProperties,
|
|
14333
|
+
accountId: this.accountId,
|
|
14334
|
+
clientId: this.config.auth.clientId,
|
|
14335
|
+
authority: canonicalAuthority.urlString,
|
|
14336
|
+
scope: scopeSet.printScopes(),
|
|
14337
|
+
redirectUri: this.getRedirectUri(request.redirectUri),
|
|
14338
|
+
prompt: getPrompt(),
|
|
14339
|
+
correlationId: this.correlationId,
|
|
14340
|
+
tokenType: request.authenticationScheme,
|
|
14341
|
+
windowTitleSubstring: document.title,
|
|
14342
|
+
extraParameters: {
|
|
14343
|
+
...request.extraQueryParameters,
|
|
14344
|
+
...request.tokenQueryParameters,
|
|
14345
|
+
},
|
|
14346
|
+
extendedExpiryToken: false,
|
|
14347
|
+
keyId: request.popKid,
|
|
14348
|
+
};
|
|
14349
|
+
// Check for PoP token requests: signPopToken should only be set to true if popKid is not set
|
|
14350
|
+
if (validatedRequest.signPopToken && !!request.popKid) {
|
|
14351
|
+
throw createBrowserAuthError(invalidPopTokenRequest);
|
|
14352
|
+
}
|
|
14353
|
+
this.handleExtraBrokerParams(validatedRequest);
|
|
14354
|
+
validatedRequest.extraParameters =
|
|
14355
|
+
validatedRequest.extraParameters || {};
|
|
14356
|
+
validatedRequest.extraParameters.telemetry =
|
|
14357
|
+
NativeConstants.MATS_TELEMETRY;
|
|
14358
|
+
if (request.authenticationScheme === AuthenticationScheme.POP) {
|
|
14359
|
+
// add POP request type
|
|
14360
|
+
const shrParameters = {
|
|
14361
|
+
resourceRequestUri: request.resourceRequestUri,
|
|
14362
|
+
resourceRequestMethod: request.resourceRequestMethod,
|
|
14363
|
+
shrClaims: request.shrClaims,
|
|
14364
|
+
shrNonce: request.shrNonce,
|
|
14394
14365
|
};
|
|
14366
|
+
const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);
|
|
14367
|
+
// generate reqCnf if not provided in the request
|
|
14368
|
+
let reqCnfData;
|
|
14369
|
+
if (!validatedRequest.keyId) {
|
|
14370
|
+
const generatedReqCnfData = await invokeAsync(popTokenGenerator.generateCnf.bind(popTokenGenerator), PerformanceEvents.PopTokenGenerateCnf, this.logger, this.performanceClient, request.correlationId)(shrParameters, this.logger);
|
|
14371
|
+
reqCnfData = generatedReqCnfData.reqCnfString;
|
|
14372
|
+
validatedRequest.keyId = generatedReqCnfData.kid;
|
|
14373
|
+
validatedRequest.signPopToken = true;
|
|
14374
|
+
}
|
|
14375
|
+
else {
|
|
14376
|
+
reqCnfData = this.browserCrypto.base64UrlEncode(JSON.stringify({ kid: validatedRequest.keyId }));
|
|
14377
|
+
validatedRequest.signPopToken = false;
|
|
14378
|
+
}
|
|
14379
|
+
// SPAs require whole string to be passed to broker
|
|
14380
|
+
validatedRequest.reqCnf = reqCnfData;
|
|
14395
14381
|
}
|
|
14396
|
-
|
|
14382
|
+
this.addRequestSKUs(validatedRequest);
|
|
14383
|
+
return validatedRequest;
|
|
14397
14384
|
}
|
|
14398
|
-
|
|
14399
|
-
|
|
14400
|
-
|
|
14401
|
-
|
|
14402
|
-
|
|
14403
|
-
|
|
14404
|
-
|
|
14405
|
-
|
|
14406
|
-
|
|
14407
|
-
|
|
14408
|
-
if (!
|
|
14409
|
-
|
|
14410
|
-
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.`);
|
|
14411
|
-
throw createBrowserAuthError(hashEmptyError);
|
|
14385
|
+
/**
|
|
14386
|
+
* Handles extra broker request parameters
|
|
14387
|
+
* @param request {NativeTokenRequest}
|
|
14388
|
+
* @private
|
|
14389
|
+
*/
|
|
14390
|
+
handleExtraBrokerParams(request) {
|
|
14391
|
+
const hasExtraBrokerParams = request.extraParameters &&
|
|
14392
|
+
request.extraParameters.hasOwnProperty(BROKER_CLIENT_ID) &&
|
|
14393
|
+
request.extraParameters.hasOwnProperty(BROKER_REDIRECT_URI) &&
|
|
14394
|
+
request.extraParameters.hasOwnProperty(CLIENT_ID);
|
|
14395
|
+
if (!request.embeddedClientId && !hasExtraBrokerParams) {
|
|
14396
|
+
return;
|
|
14412
14397
|
}
|
|
14413
|
-
|
|
14414
|
-
|
|
14415
|
-
|
|
14416
|
-
|
|
14398
|
+
let child_client_id = "";
|
|
14399
|
+
const child_redirect_uri = request.redirectUri;
|
|
14400
|
+
if (request.embeddedClientId) {
|
|
14401
|
+
request.redirectUri = this.config.auth.redirectUri;
|
|
14402
|
+
child_client_id = request.embeddedClientId;
|
|
14417
14403
|
}
|
|
14418
|
-
|
|
14419
|
-
|
|
14420
|
-
|
|
14421
|
-
|
|
14422
|
-
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
14426
|
-
|
|
14427
|
-
|
|
14428
|
-
|
|
14429
|
-
|
|
14430
|
-
|
|
14431
|
-
|
|
14432
|
-
if (platformStateObj.interactionType !== interactionType) {
|
|
14433
|
-
throw createBrowserAuthError(stateInteractionTypeMismatch);
|
|
14404
|
+
else if (request.extraParameters) {
|
|
14405
|
+
request.redirectUri =
|
|
14406
|
+
request.extraParameters[BROKER_REDIRECT_URI];
|
|
14407
|
+
child_client_id =
|
|
14408
|
+
request.extraParameters[CLIENT_ID];
|
|
14409
|
+
}
|
|
14410
|
+
request.extraParameters = {
|
|
14411
|
+
child_client_id,
|
|
14412
|
+
child_redirect_uri,
|
|
14413
|
+
};
|
|
14414
|
+
this.performanceClient?.addFields({
|
|
14415
|
+
embeddedClientId: child_client_id,
|
|
14416
|
+
embeddedRedirectUri: child_redirect_uri,
|
|
14417
|
+
}, request.correlationId);
|
|
14434
14418
|
}
|
|
14435
14419
|
}
|
|
14436
14420
|
|
|
@@ -14494,9 +14478,147 @@
|
|
|
14494
14478
|
throw createClientConfigurationError(pkceParamsMissing);
|
|
14495
14479
|
}
|
|
14496
14480
|
const parameters = await invokeAsync(getStandardParameters, PerformanceEvents.GetStandardParams, logger, performanceClient, request.correlationId)(config, authority, request, logger, performanceClient);
|
|
14497
|
-
|
|
14481
|
+
addResponseType(parameters, OAuthResponseType.CODE);
|
|
14498
14482
|
addCodeChallengeParams(parameters, request.codeChallenge, Constants.S256_CODE_CHALLENGE_METHOD);
|
|
14483
|
+
addExtraQueryParameters(parameters, request.extraQueryParameters || {});
|
|
14499
14484
|
return getAuthorizeUrl(authority, parameters);
|
|
14485
|
+
}
|
|
14486
|
+
/**
|
|
14487
|
+
* Gets the form that will be posted to /authorize with request parameters when using EAR
|
|
14488
|
+
*/
|
|
14489
|
+
async function getEARForm(frame, config, authority, request, logger, performanceClient) {
|
|
14490
|
+
if (!request.earJwk) {
|
|
14491
|
+
throw createBrowserAuthError(earJwkEmpty);
|
|
14492
|
+
}
|
|
14493
|
+
const parameters = await getStandardParameters(config, authority, request, logger, performanceClient);
|
|
14494
|
+
addResponseType(parameters, OAuthResponseType.IDTOKEN_TOKEN_REFRESHTOKEN);
|
|
14495
|
+
addEARParameters(parameters, request.earJwk);
|
|
14496
|
+
const queryParams = new Map();
|
|
14497
|
+
addExtraQueryParameters(queryParams, request.extraQueryParameters || {});
|
|
14498
|
+
const url = getAuthorizeUrl(authority, queryParams);
|
|
14499
|
+
return createForm(frame, url, parameters);
|
|
14500
|
+
}
|
|
14501
|
+
/**
|
|
14502
|
+
* Creates form element in the provided document with auth parameters in the post body
|
|
14503
|
+
* @param frame
|
|
14504
|
+
* @param authorizeUrl
|
|
14505
|
+
* @param parameters
|
|
14506
|
+
* @returns
|
|
14507
|
+
*/
|
|
14508
|
+
function createForm(frame, authorizeUrl, parameters) {
|
|
14509
|
+
const form = frame.createElement("form");
|
|
14510
|
+
form.method = "post";
|
|
14511
|
+
form.action = authorizeUrl;
|
|
14512
|
+
parameters.forEach((value, key) => {
|
|
14513
|
+
const param = frame.createElement("input");
|
|
14514
|
+
param.hidden = true;
|
|
14515
|
+
param.name = key;
|
|
14516
|
+
param.value = value;
|
|
14517
|
+
form.appendChild(param);
|
|
14518
|
+
});
|
|
14519
|
+
frame.body.appendChild(form);
|
|
14520
|
+
return form;
|
|
14521
|
+
}
|
|
14522
|
+
/**
|
|
14523
|
+
* Response handler when server returns accountId on the /authorize request
|
|
14524
|
+
* @param request
|
|
14525
|
+
* @param accountId
|
|
14526
|
+
* @param apiId
|
|
14527
|
+
* @param config
|
|
14528
|
+
* @param browserStorage
|
|
14529
|
+
* @param nativeStorage
|
|
14530
|
+
* @param eventHandler
|
|
14531
|
+
* @param logger
|
|
14532
|
+
* @param performanceClient
|
|
14533
|
+
* @param nativeMessageHandler
|
|
14534
|
+
* @returns
|
|
14535
|
+
*/
|
|
14536
|
+
async function handleResponsePlatformBroker(request, accountId, apiId, config, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler) {
|
|
14537
|
+
if (!nativeMessageHandler) {
|
|
14538
|
+
throw createBrowserAuthError(nativeConnectionNotEstablished);
|
|
14539
|
+
}
|
|
14540
|
+
const browserCrypto = new CryptoOps(logger, performanceClient);
|
|
14541
|
+
const nativeInteractionClient = new NativeInteractionClient(config, browserStorage, browserCrypto, logger, eventHandler, config.system.navigationClient, apiId, performanceClient, nativeMessageHandler, accountId, nativeStorage, request.correlationId);
|
|
14542
|
+
const { userRequestState } = ProtocolUtils.parseRequestState(browserCrypto, request.state);
|
|
14543
|
+
return invokeAsync(nativeInteractionClient.acquireToken.bind(nativeInteractionClient), PerformanceEvents.NativeInteractionClientAcquireToken, logger, performanceClient, request.correlationId)({
|
|
14544
|
+
...request,
|
|
14545
|
+
state: userRequestState,
|
|
14546
|
+
prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
|
|
14547
|
+
});
|
|
14548
|
+
}
|
|
14549
|
+
/**
|
|
14550
|
+
* Response handler when server returns code on the /authorize request
|
|
14551
|
+
* @param request
|
|
14552
|
+
* @param response
|
|
14553
|
+
* @param codeVerifier
|
|
14554
|
+
* @param authClient
|
|
14555
|
+
* @param browserStorage
|
|
14556
|
+
* @param logger
|
|
14557
|
+
* @param performanceClient
|
|
14558
|
+
* @returns
|
|
14559
|
+
*/
|
|
14560
|
+
async function handleResponseCode(request, response, codeVerifier, apiId, config, authClient, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler) {
|
|
14561
|
+
// Remove throttle if it exists
|
|
14562
|
+
ThrottlingUtils.removeThrottle(browserStorage, config.auth.clientId, request);
|
|
14563
|
+
if (response.accountId) {
|
|
14564
|
+
return invokeAsync(handleResponsePlatformBroker, PerformanceEvents.HandleResponsePlatformBroker, logger, performanceClient, request.correlationId)(request, response.accountId, apiId, config, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler);
|
|
14565
|
+
}
|
|
14566
|
+
const authCodeRequest = {
|
|
14567
|
+
...request,
|
|
14568
|
+
code: response.code || "",
|
|
14569
|
+
codeVerifier: codeVerifier,
|
|
14570
|
+
};
|
|
14571
|
+
// Create popup interaction handler.
|
|
14572
|
+
const interactionHandler = new InteractionHandler(authClient, browserStorage, authCodeRequest, logger, performanceClient);
|
|
14573
|
+
// Handle response from hash string.
|
|
14574
|
+
const result = await invokeAsync(interactionHandler.handleCodeResponse.bind(interactionHandler), PerformanceEvents.HandleCodeResponse, logger, performanceClient, request.correlationId)(response, request);
|
|
14575
|
+
return result;
|
|
14576
|
+
}
|
|
14577
|
+
/**
|
|
14578
|
+
* Response handler when server returns ear_jwe on the /authorize request
|
|
14579
|
+
* @param request
|
|
14580
|
+
* @param response
|
|
14581
|
+
* @param apiId
|
|
14582
|
+
* @param config
|
|
14583
|
+
* @param authority
|
|
14584
|
+
* @param browserStorage
|
|
14585
|
+
* @param nativeStorage
|
|
14586
|
+
* @param eventHandler
|
|
14587
|
+
* @param logger
|
|
14588
|
+
* @param performanceClient
|
|
14589
|
+
* @param nativeMessageHandler
|
|
14590
|
+
* @returns
|
|
14591
|
+
*/
|
|
14592
|
+
async function handleResponseEAR(request, response, apiId, config, authority, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler) {
|
|
14593
|
+
// Remove throttle if it exists
|
|
14594
|
+
ThrottlingUtils.removeThrottle(browserStorage, config.auth.clientId, request);
|
|
14595
|
+
// Validate state & check response for errors
|
|
14596
|
+
validateAuthorizationResponse(response, request.state);
|
|
14597
|
+
if (!response.ear_jwe) {
|
|
14598
|
+
throw createBrowserAuthError(earJweEmpty);
|
|
14599
|
+
}
|
|
14600
|
+
if (!request.earJwk) {
|
|
14601
|
+
throw createBrowserAuthError(earJwkEmpty);
|
|
14602
|
+
}
|
|
14603
|
+
const decryptedData = JSON.parse(await invokeAsync(decryptEarResponse, PerformanceEvents.DecryptEarResponse, logger, performanceClient, request.correlationId)(request.earJwk, response.ear_jwe));
|
|
14604
|
+
if (decryptedData.accountId) {
|
|
14605
|
+
return invokeAsync(handleResponsePlatformBroker, PerformanceEvents.HandleResponsePlatformBroker, logger, performanceClient, request.correlationId)(request, decryptedData.accountId, apiId, config, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler);
|
|
14606
|
+
}
|
|
14607
|
+
const responseHandler = new ResponseHandler(config.auth.clientId, browserStorage, new CryptoOps(logger, performanceClient), logger, null, null, performanceClient);
|
|
14608
|
+
// Validate response. This function throws a server error if an error is returned by the server.
|
|
14609
|
+
responseHandler.validateTokenResponse(decryptedData);
|
|
14610
|
+
// Temporary until response handler is refactored to be more flow agnostic.
|
|
14611
|
+
const additionalData = {
|
|
14612
|
+
code: "",
|
|
14613
|
+
state: request.state,
|
|
14614
|
+
nonce: request.nonce,
|
|
14615
|
+
client_info: decryptedData.client_info,
|
|
14616
|
+
cloud_graph_host_name: decryptedData.cloud_graph_host_name,
|
|
14617
|
+
cloud_instance_host_name: decryptedData.cloud_instance_host_name,
|
|
14618
|
+
cloud_instance_name: decryptedData.cloud_instance_name,
|
|
14619
|
+
msgraph_host: decryptedData.msgraph_host,
|
|
14620
|
+
};
|
|
14621
|
+
return (await invokeAsync(responseHandler.handleServerTokenResponse.bind(responseHandler), PerformanceEvents.HandleServerTokenResponse, logger, performanceClient, request.correlationId)(decryptedData, authority, nowSeconds(), request, additionalData, undefined, undefined, undefined, undefined));
|
|
14500
14622
|
}
|
|
14501
14623
|
|
|
14502
14624
|
/*
|
|
@@ -14564,6 +14686,7 @@
|
|
|
14564
14686
|
// Properly sets this reference for the unload event.
|
|
14565
14687
|
this.unloadWindow = this.unloadWindow.bind(this);
|
|
14566
14688
|
this.nativeStorage = nativeStorageImpl;
|
|
14689
|
+
this.eventHandler = eventHandler;
|
|
14567
14690
|
}
|
|
14568
14691
|
/**
|
|
14569
14692
|
* Acquires tokens by opening a popup window to the /authorize endpoint of the authority
|
|
@@ -14639,11 +14762,7 @@
|
|
|
14639
14762
|
*/
|
|
14640
14763
|
async acquireTokenPopupAsync(request, popupParams, pkceCodes) {
|
|
14641
14764
|
this.logger.verbose("acquireTokenPopupAsync called");
|
|
14642
|
-
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenPopup);
|
|
14643
14765
|
const validRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, this.correlationId)(request, exports.InteractionType.Popup);
|
|
14644
|
-
const pkce = pkceCodes ||
|
|
14645
|
-
(await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, this.correlationId)(this.performanceClient, this.logger, this.correlationId));
|
|
14646
|
-
validRequest.codeChallenge = pkce.challenge;
|
|
14647
14766
|
/*
|
|
14648
14767
|
* Skip pre-connect for async popups to reduce time between user interaction and popup window creation to avoid
|
|
14649
14768
|
* popup from being blocked by browsers with shorter popup timers
|
|
@@ -14651,65 +14770,49 @@
|
|
|
14651
14770
|
if (popupParams.popup) {
|
|
14652
14771
|
preconnect(validRequest.authority);
|
|
14653
14772
|
}
|
|
14773
|
+
const isPlatformBroker = NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
|
|
14774
|
+
validRequest.platformBroker = isPlatformBroker;
|
|
14775
|
+
if (this.config.auth.protocolMode === ProtocolMode.EAR) {
|
|
14776
|
+
return this.executeEarFlow(validRequest, popupParams);
|
|
14777
|
+
}
|
|
14778
|
+
else {
|
|
14779
|
+
return this.executeCodeFlow(validRequest, popupParams, pkceCodes);
|
|
14780
|
+
}
|
|
14781
|
+
}
|
|
14782
|
+
/**
|
|
14783
|
+
* Executes auth code + PKCE flow
|
|
14784
|
+
* @param request
|
|
14785
|
+
* @param popupParams
|
|
14786
|
+
* @param pkceCodes
|
|
14787
|
+
* @returns
|
|
14788
|
+
*/
|
|
14789
|
+
async executeCodeFlow(request, popupParams, pkceCodes) {
|
|
14790
|
+
const correlationId = request.correlationId;
|
|
14791
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenPopup);
|
|
14792
|
+
const pkce = pkceCodes ||
|
|
14793
|
+
(await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, correlationId)(this.performanceClient, this.logger, correlationId));
|
|
14794
|
+
const popupRequest = {
|
|
14795
|
+
...request,
|
|
14796
|
+
codeChallenge: pkce.challenge,
|
|
14797
|
+
};
|
|
14654
14798
|
try {
|
|
14655
14799
|
// Initialize the client
|
|
14656
|
-
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient,
|
|
14800
|
+
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, correlationId)({
|
|
14657
14801
|
serverTelemetryManager,
|
|
14658
|
-
requestAuthority:
|
|
14659
|
-
requestAzureCloudOptions:
|
|
14660
|
-
requestExtraQueryParameters:
|
|
14661
|
-
account:
|
|
14802
|
+
requestAuthority: popupRequest.authority,
|
|
14803
|
+
requestAzureCloudOptions: popupRequest.azureCloudOptions,
|
|
14804
|
+
requestExtraQueryParameters: popupRequest.extraQueryParameters,
|
|
14805
|
+
account: popupRequest.account,
|
|
14662
14806
|
});
|
|
14663
|
-
const isPlatformBroker = NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
|
|
14664
|
-
// Start measurement for server calls with native brokering enabled
|
|
14665
|
-
let fetchNativeAccountIdMeasurement;
|
|
14666
|
-
if (isPlatformBroker) {
|
|
14667
|
-
fetchNativeAccountIdMeasurement =
|
|
14668
|
-
this.performanceClient.startMeasurement(PerformanceEvents.FetchAccountIdWithNativeBroker, request.correlationId);
|
|
14669
|
-
}
|
|
14670
14807
|
// Create acquire token url.
|
|
14671
|
-
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient,
|
|
14672
|
-
...validRequest,
|
|
14673
|
-
platformBroker: isPlatformBroker,
|
|
14674
|
-
}, this.logger, this.performanceClient);
|
|
14808
|
+
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, correlationId)(this.config, authClient.authority, popupRequest, this.logger, this.performanceClient);
|
|
14675
14809
|
// Show the UI once the url has been created. Get the window handle for the popup.
|
|
14676
14810
|
const popupWindow = this.initiateAuthRequest(navigateUrl, popupParams);
|
|
14677
14811
|
this.eventHandler.emitEvent(EventType.POPUP_OPENED, exports.InteractionType.Popup, { popupWindow }, null);
|
|
14678
14812
|
// Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
|
|
14679
14813
|
const responseString = await this.monitorPopupForHash(popupWindow, popupParams.popupWindowParent);
|
|
14680
14814
|
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, this.correlationId)(responseString, this.config.auth.OIDCOptions.serverResponseType, this.logger);
|
|
14681
|
-
|
|
14682
|
-
ThrottlingUtils.removeThrottle(this.browserStorage, this.config.auth.clientId, validRequest);
|
|
14683
|
-
if (serverParams.accountId) {
|
|
14684
|
-
this.logger.verbose("Account id found in hash, calling WAM for token");
|
|
14685
|
-
// end measurement for server call with native brokering enabled
|
|
14686
|
-
if (fetchNativeAccountIdMeasurement) {
|
|
14687
|
-
fetchNativeAccountIdMeasurement.end({
|
|
14688
|
-
success: true,
|
|
14689
|
-
isNativeBroker: true,
|
|
14690
|
-
});
|
|
14691
|
-
}
|
|
14692
|
-
if (!this.nativeMessageHandler) {
|
|
14693
|
-
throw createBrowserAuthError(nativeConnectionNotEstablished);
|
|
14694
|
-
}
|
|
14695
|
-
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);
|
|
14696
|
-
const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, validRequest.state);
|
|
14697
|
-
return await nativeInteractionClient.acquireToken({
|
|
14698
|
-
...validRequest,
|
|
14699
|
-
state: userRequestState,
|
|
14700
|
-
prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
|
|
14701
|
-
});
|
|
14702
|
-
}
|
|
14703
|
-
const authCodeRequest = {
|
|
14704
|
-
...validRequest,
|
|
14705
|
-
code: serverParams.code || "",
|
|
14706
|
-
codeVerifier: pkce.verifier,
|
|
14707
|
-
};
|
|
14708
|
-
// Create popup interaction handler.
|
|
14709
|
-
const interactionHandler = new InteractionHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.performanceClient);
|
|
14710
|
-
// Handle response from hash string.
|
|
14711
|
-
const result = await interactionHandler.handleCodeResponse(serverParams, validRequest);
|
|
14712
|
-
return result;
|
|
14815
|
+
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);
|
|
14713
14816
|
}
|
|
14714
14817
|
catch (e) {
|
|
14715
14818
|
// Close the synchronous popup if an error is thrown before the window unload event is registered
|
|
@@ -14721,6 +14824,32 @@
|
|
|
14721
14824
|
throw e;
|
|
14722
14825
|
}
|
|
14723
14826
|
}
|
|
14827
|
+
/**
|
|
14828
|
+
* Executes EAR flow
|
|
14829
|
+
* @param request
|
|
14830
|
+
*/
|
|
14831
|
+
async executeEarFlow(request, popupParams) {
|
|
14832
|
+
const correlationId = request.correlationId;
|
|
14833
|
+
// Get the frame handle for the silent request
|
|
14834
|
+
const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, correlationId)({
|
|
14835
|
+
requestAuthority: request.authority,
|
|
14836
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
14837
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
14838
|
+
account: request.account,
|
|
14839
|
+
});
|
|
14840
|
+
const earJwk = await invokeAsync(generateEarKey, PerformanceEvents.GenerateEarKey, this.logger, this.performanceClient, correlationId)();
|
|
14841
|
+
const popupRequest = {
|
|
14842
|
+
...request,
|
|
14843
|
+
earJwk: earJwk,
|
|
14844
|
+
};
|
|
14845
|
+
const popupWindow = popupParams.popup || this.openPopup("about:blank", popupParams);
|
|
14846
|
+
const form = await getEARForm(popupWindow.document, this.config, discoveredAuthority, popupRequest, this.logger, this.performanceClient);
|
|
14847
|
+
form.submit();
|
|
14848
|
+
// Monitor the popup for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
|
|
14849
|
+
const responseString = await invokeAsync(this.monitorPopupForHash.bind(this), PerformanceEvents.SilentHandlerMonitorIframeForHash, this.logger, this.performanceClient, correlationId)(popupWindow, popupParams.popupWindowParent);
|
|
14850
|
+
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, this.correlationId)(responseString, this.config.auth.OIDCOptions.serverResponseType, this.logger);
|
|
14851
|
+
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);
|
|
14852
|
+
}
|
|
14724
14853
|
/**
|
|
14725
14854
|
*
|
|
14726
14855
|
* @param validRequest
|
|
@@ -14796,7 +14925,6 @@
|
|
|
14796
14925
|
e.setCorrelationId(this.correlationId);
|
|
14797
14926
|
serverTelemetryManager.cacheFailedRequest(e);
|
|
14798
14927
|
}
|
|
14799
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
14800
14928
|
this.eventHandler.emitEvent(EventType.LOGOUT_FAILURE, exports.InteractionType.Popup, null, e);
|
|
14801
14929
|
this.eventHandler.emitEvent(EventType.LOGOUT_END, exports.InteractionType.Popup);
|
|
14802
14930
|
throw e;
|
|
@@ -14908,7 +15036,6 @@
|
|
|
14908
15036
|
}
|
|
14909
15037
|
catch (e) {
|
|
14910
15038
|
this.logger.error("error opening popup " + e.message);
|
|
14911
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
14912
15039
|
throw createBrowserAuthError(popupWindowError);
|
|
14913
15040
|
}
|
|
14914
15041
|
}
|
|
@@ -14966,7 +15093,6 @@
|
|
|
14966
15093
|
* Event callback to unload main window.
|
|
14967
15094
|
*/
|
|
14968
15095
|
unloadWindow(e) {
|
|
14969
|
-
this.browserStorage.cleanRequestByInteractionType(exports.InteractionType.Popup);
|
|
14970
15096
|
if (this.currentWindow) {
|
|
14971
15097
|
this.currentWindow.close();
|
|
14972
15098
|
}
|
|
@@ -14982,8 +15108,6 @@
|
|
|
14982
15108
|
popupWindow.close();
|
|
14983
15109
|
// Remove window unload function
|
|
14984
15110
|
popupWindowParent.removeEventListener("beforeunload", this.unloadWindow);
|
|
14985
|
-
// Interaction is completed - remove interaction status.
|
|
14986
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
14987
15111
|
}
|
|
14988
15112
|
/**
|
|
14989
15113
|
* Generates the name for the popup based on the client id and request
|
|
@@ -15004,141 +15128,6 @@
|
|
|
15004
15128
|
}
|
|
15005
15129
|
}
|
|
15006
15130
|
|
|
15007
|
-
/*
|
|
15008
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
15009
|
-
* Licensed under the MIT License.
|
|
15010
|
-
*/
|
|
15011
|
-
class RedirectHandler {
|
|
15012
|
-
constructor(authCodeModule, storageImpl, authCodeRequest, logger, performanceClient) {
|
|
15013
|
-
this.authModule = authCodeModule;
|
|
15014
|
-
this.browserStorage = storageImpl;
|
|
15015
|
-
this.authCodeRequest = authCodeRequest;
|
|
15016
|
-
this.logger = logger;
|
|
15017
|
-
this.performanceClient = performanceClient;
|
|
15018
|
-
}
|
|
15019
|
-
/**
|
|
15020
|
-
* Redirects window to given URL.
|
|
15021
|
-
* @param urlNavigate
|
|
15022
|
-
*/
|
|
15023
|
-
async initiateAuthRequest(requestUrl, params) {
|
|
15024
|
-
this.logger.verbose("RedirectHandler.initiateAuthRequest called");
|
|
15025
|
-
// Navigate if valid URL
|
|
15026
|
-
if (requestUrl) {
|
|
15027
|
-
// Cache start page, returns to this page after redirectUri if navigateToLoginRequestUrl is true
|
|
15028
|
-
if (params.redirectStartPage) {
|
|
15029
|
-
this.logger.verbose("RedirectHandler.initiateAuthRequest: redirectStartPage set, caching start page");
|
|
15030
|
-
this.browserStorage.setTemporaryCache(TemporaryCacheKeys.ORIGIN_URI, params.redirectStartPage, true);
|
|
15031
|
-
}
|
|
15032
|
-
// Set interaction status in the library.
|
|
15033
|
-
this.browserStorage.setTemporaryCache(TemporaryCacheKeys.CORRELATION_ID, this.authCodeRequest.correlationId, true);
|
|
15034
|
-
this.browserStorage.cacheCodeRequest(this.authCodeRequest);
|
|
15035
|
-
this.logger.infoPii(`RedirectHandler.initiateAuthRequest: Navigate to: ${requestUrl}`);
|
|
15036
|
-
const navigationOptions = {
|
|
15037
|
-
apiId: ApiId.acquireTokenRedirect,
|
|
15038
|
-
timeout: params.redirectTimeout,
|
|
15039
|
-
noHistory: false,
|
|
15040
|
-
};
|
|
15041
|
-
// If onRedirectNavigate is implemented, invoke it and provide requestUrl
|
|
15042
|
-
if (typeof params.onRedirectNavigate === "function") {
|
|
15043
|
-
this.logger.verbose("RedirectHandler.initiateAuthRequest: Invoking onRedirectNavigate callback");
|
|
15044
|
-
const navigate = params.onRedirectNavigate(requestUrl);
|
|
15045
|
-
// Returning false from onRedirectNavigate will stop navigation
|
|
15046
|
-
if (navigate !== false) {
|
|
15047
|
-
this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate did not return false, navigating");
|
|
15048
|
-
await params.navigationClient.navigateExternal(requestUrl, navigationOptions);
|
|
15049
|
-
return;
|
|
15050
|
-
}
|
|
15051
|
-
else {
|
|
15052
|
-
this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate returned false, stopping navigation");
|
|
15053
|
-
return;
|
|
15054
|
-
}
|
|
15055
|
-
}
|
|
15056
|
-
else {
|
|
15057
|
-
// Navigate window to request URL
|
|
15058
|
-
this.logger.verbose("RedirectHandler.initiateAuthRequest: Navigating window to navigate url");
|
|
15059
|
-
await params.navigationClient.navigateExternal(requestUrl, navigationOptions);
|
|
15060
|
-
return;
|
|
15061
|
-
}
|
|
15062
|
-
}
|
|
15063
|
-
else {
|
|
15064
|
-
// Throw error if request URL is empty.
|
|
15065
|
-
this.logger.info("RedirectHandler.initiateAuthRequest: Navigate url is empty");
|
|
15066
|
-
throw createBrowserAuthError(emptyNavigateUri);
|
|
15067
|
-
}
|
|
15068
|
-
}
|
|
15069
|
-
/**
|
|
15070
|
-
* Handle authorization code response in the window.
|
|
15071
|
-
* @param hash
|
|
15072
|
-
*/
|
|
15073
|
-
async handleCodeResponse(response, state) {
|
|
15074
|
-
this.logger.verbose("RedirectHandler.handleCodeResponse called");
|
|
15075
|
-
// Interaction is completed - remove interaction status.
|
|
15076
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
15077
|
-
// Handle code response.
|
|
15078
|
-
const stateKey = this.browserStorage.generateStateKey(state);
|
|
15079
|
-
const requestState = this.browserStorage.getTemporaryCache(stateKey);
|
|
15080
|
-
if (!requestState) {
|
|
15081
|
-
throw createClientAuthError(stateNotFound, "Cached State");
|
|
15082
|
-
}
|
|
15083
|
-
let authCodeResponse;
|
|
15084
|
-
try {
|
|
15085
|
-
authCodeResponse = getAuthorizationCodePayload(response, requestState);
|
|
15086
|
-
}
|
|
15087
|
-
catch (e) {
|
|
15088
|
-
if (e instanceof ServerError &&
|
|
15089
|
-
e.subError === userCancelled) {
|
|
15090
|
-
// Translate server error caused by user closing native prompt to corresponding first class MSAL error
|
|
15091
|
-
throw createBrowserAuthError(userCancelled);
|
|
15092
|
-
}
|
|
15093
|
-
else {
|
|
15094
|
-
throw e;
|
|
15095
|
-
}
|
|
15096
|
-
}
|
|
15097
|
-
// Get cached items
|
|
15098
|
-
const nonceKey = this.browserStorage.generateNonceKey(requestState);
|
|
15099
|
-
const cachedNonce = this.browserStorage.getTemporaryCache(nonceKey);
|
|
15100
|
-
// Assign code to request
|
|
15101
|
-
this.authCodeRequest.code = authCodeResponse.code;
|
|
15102
|
-
// Check for new cloud instance
|
|
15103
|
-
if (authCodeResponse.cloud_instance_host_name) {
|
|
15104
|
-
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);
|
|
15105
|
-
}
|
|
15106
|
-
authCodeResponse.nonce = cachedNonce || undefined;
|
|
15107
|
-
authCodeResponse.state = requestState;
|
|
15108
|
-
// Add CCS parameters if available
|
|
15109
|
-
if (authCodeResponse.client_info) {
|
|
15110
|
-
this.authCodeRequest.clientInfo = authCodeResponse.client_info;
|
|
15111
|
-
}
|
|
15112
|
-
else {
|
|
15113
|
-
const cachedCcsCred = this.checkCcsCredentials();
|
|
15114
|
-
if (cachedCcsCred) {
|
|
15115
|
-
this.authCodeRequest.ccsCredential = cachedCcsCred;
|
|
15116
|
-
}
|
|
15117
|
-
}
|
|
15118
|
-
// Acquire token with retrieved code.
|
|
15119
|
-
const tokenResponse = (await this.authModule.acquireToken(this.authCodeRequest, authCodeResponse));
|
|
15120
|
-
this.browserStorage.cleanRequestByState(state);
|
|
15121
|
-
return tokenResponse;
|
|
15122
|
-
}
|
|
15123
|
-
/**
|
|
15124
|
-
* Looks up ccs creds in the cache
|
|
15125
|
-
*/
|
|
15126
|
-
checkCcsCredentials() {
|
|
15127
|
-
// Look up ccs credential in temp cache
|
|
15128
|
-
const cachedCcsCred = this.browserStorage.getTemporaryCache(TemporaryCacheKeys.CCS_CREDENTIAL, true);
|
|
15129
|
-
if (cachedCcsCred) {
|
|
15130
|
-
try {
|
|
15131
|
-
return JSON.parse(cachedCcsCred);
|
|
15132
|
-
}
|
|
15133
|
-
catch (e) {
|
|
15134
|
-
this.authModule.logger.error("Cache credential could not be parsed");
|
|
15135
|
-
this.authModule.logger.errorPii(`Cache credential could not be parsed: ${cachedCcsCred}`);
|
|
15136
|
-
}
|
|
15137
|
-
}
|
|
15138
|
-
return null;
|
|
15139
|
-
}
|
|
15140
|
-
}
|
|
15141
|
-
|
|
15142
15131
|
/*
|
|
15143
15132
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
15144
15133
|
* Licensed under the MIT License.
|
|
@@ -15166,62 +15155,96 @@
|
|
|
15166
15155
|
*/
|
|
15167
15156
|
async acquireToken(request) {
|
|
15168
15157
|
const validRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, this.correlationId)(request, exports.InteractionType.Redirect);
|
|
15169
|
-
|
|
15170
|
-
|
|
15171
|
-
this.browserStorage.updateCacheEntries(validRequest.state, validRequest.nonce, validRequest.authority, validRequest.loginHint || "", validRequest.account || null);
|
|
15172
|
-
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenRedirect);
|
|
15158
|
+
validRequest.platformBroker =
|
|
15159
|
+
NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
|
|
15173
15160
|
const handleBackButton = (event) => {
|
|
15174
15161
|
// Clear temporary cache if the back button is clicked during the redirect flow.
|
|
15175
15162
|
if (event.persisted) {
|
|
15176
15163
|
this.logger.verbose("Page was restored from back/forward cache. Clearing temporary cache.");
|
|
15177
|
-
this.browserStorage.
|
|
15164
|
+
this.browserStorage.resetRequestCache();
|
|
15178
15165
|
this.eventHandler.emitEvent(EventType.RESTORE_FROM_BFCACHE, exports.InteractionType.Redirect);
|
|
15179
15166
|
}
|
|
15180
15167
|
};
|
|
15168
|
+
const redirectStartPage = this.getRedirectStartPage(request.redirectStartPage);
|
|
15169
|
+
this.logger.verbosePii(`Redirect start page: ${redirectStartPage}`);
|
|
15170
|
+
// Cache start page, returns to this page after redirectUri if navigateToLoginRequestUrl is true
|
|
15171
|
+
this.browserStorage.setTemporaryCache(TemporaryCacheKeys.ORIGIN_URI, redirectStartPage, true);
|
|
15172
|
+
// Clear temporary cache if the back button is clicked during the redirect flow.
|
|
15173
|
+
window.addEventListener("pageshow", handleBackButton);
|
|
15174
|
+
try {
|
|
15175
|
+
if (this.config.auth.protocolMode === ProtocolMode.EAR) {
|
|
15176
|
+
await this.executeEarFlow(validRequest);
|
|
15177
|
+
}
|
|
15178
|
+
else {
|
|
15179
|
+
await this.executeCodeFlow(validRequest, request.onRedirectNavigate);
|
|
15180
|
+
}
|
|
15181
|
+
}
|
|
15182
|
+
catch (e) {
|
|
15183
|
+
if (e instanceof AuthError) {
|
|
15184
|
+
e.setCorrelationId(this.correlationId);
|
|
15185
|
+
}
|
|
15186
|
+
window.removeEventListener("pageshow", handleBackButton);
|
|
15187
|
+
throw e;
|
|
15188
|
+
}
|
|
15189
|
+
}
|
|
15190
|
+
/**
|
|
15191
|
+
* Executes auth code + PKCE flow
|
|
15192
|
+
* @param request
|
|
15193
|
+
* @returns
|
|
15194
|
+
*/
|
|
15195
|
+
async executeCodeFlow(request, onRedirectNavigate) {
|
|
15196
|
+
const correlationId = request.correlationId;
|
|
15197
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenRedirect);
|
|
15198
|
+
const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, correlationId)(this.performanceClient, this.logger, correlationId);
|
|
15199
|
+
const redirectRequest = {
|
|
15200
|
+
...request,
|
|
15201
|
+
codeChallenge: pkceCodes.challenge,
|
|
15202
|
+
};
|
|
15203
|
+
this.browserStorage.cacheAuthorizeRequest(redirectRequest, pkceCodes.verifier);
|
|
15181
15204
|
try {
|
|
15182
15205
|
// Initialize the client
|
|
15183
15206
|
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)({
|
|
15184
15207
|
serverTelemetryManager,
|
|
15185
|
-
requestAuthority:
|
|
15186
|
-
requestAzureCloudOptions:
|
|
15187
|
-
requestExtraQueryParameters:
|
|
15188
|
-
account:
|
|
15208
|
+
requestAuthority: redirectRequest.authority,
|
|
15209
|
+
requestAzureCloudOptions: redirectRequest.azureCloudOptions,
|
|
15210
|
+
requestExtraQueryParameters: redirectRequest.extraQueryParameters,
|
|
15211
|
+
account: redirectRequest.account,
|
|
15189
15212
|
});
|
|
15190
|
-
const authCodeRequest = {
|
|
15191
|
-
...validRequest,
|
|
15192
|
-
code: "",
|
|
15193
|
-
codeVerifier: pkceCodes.verifier,
|
|
15194
|
-
};
|
|
15195
|
-
// Create redirect interaction handler.
|
|
15196
|
-
const interactionHandler = new RedirectHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.performanceClient);
|
|
15197
15213
|
// Create acquire token url.
|
|
15198
|
-
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient,
|
|
15199
|
-
...validRequest,
|
|
15200
|
-
platformBroker: NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme),
|
|
15201
|
-
}, this.logger, this.performanceClient);
|
|
15202
|
-
const redirectStartPage = this.getRedirectStartPage(request.redirectStartPage);
|
|
15203
|
-
this.logger.verbosePii(`Redirect start page: ${redirectStartPage}`);
|
|
15204
|
-
// Clear temporary cache if the back button is clicked during the redirect flow.
|
|
15205
|
-
window.addEventListener("pageshow", handleBackButton);
|
|
15214
|
+
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, request.correlationId)(this.config, authClient.authority, redirectRequest, this.logger, this.performanceClient);
|
|
15206
15215
|
// Show the UI once the url has been created. Response will come back in the hash, which will be handled in the handleRedirectCallback function.
|
|
15207
|
-
return await
|
|
15208
|
-
navigationClient: this.navigationClient,
|
|
15209
|
-
redirectTimeout: this.config.system.redirectNavigationTimeout,
|
|
15210
|
-
redirectStartPage: redirectStartPage,
|
|
15211
|
-
onRedirectNavigate: request.onRedirectNavigate ||
|
|
15212
|
-
this.config.auth.onRedirectNavigate,
|
|
15213
|
-
});
|
|
15216
|
+
return await this.initiateAuthRequest(navigateUrl, onRedirectNavigate);
|
|
15214
15217
|
}
|
|
15215
15218
|
catch (e) {
|
|
15216
15219
|
if (e instanceof AuthError) {
|
|
15217
15220
|
e.setCorrelationId(this.correlationId);
|
|
15218
15221
|
serverTelemetryManager.cacheFailedRequest(e);
|
|
15219
15222
|
}
|
|
15220
|
-
window.removeEventListener("pageshow", handleBackButton);
|
|
15221
|
-
this.browserStorage.cleanRequestByState(validRequest.state);
|
|
15222
15223
|
throw e;
|
|
15223
15224
|
}
|
|
15224
15225
|
}
|
|
15226
|
+
/**
|
|
15227
|
+
* Executes EAR flow
|
|
15228
|
+
* @param request
|
|
15229
|
+
*/
|
|
15230
|
+
async executeEarFlow(request) {
|
|
15231
|
+
const correlationId = request.correlationId;
|
|
15232
|
+
// Get the frame handle for the silent request
|
|
15233
|
+
const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, correlationId)({
|
|
15234
|
+
requestAuthority: request.authority,
|
|
15235
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
15236
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
15237
|
+
account: request.account,
|
|
15238
|
+
});
|
|
15239
|
+
const earJwk = await invokeAsync(generateEarKey, PerformanceEvents.GenerateEarKey, this.logger, this.performanceClient, correlationId)();
|
|
15240
|
+
const redirectRequest = {
|
|
15241
|
+
...request,
|
|
15242
|
+
earJwk: earJwk,
|
|
15243
|
+
};
|
|
15244
|
+
this.browserStorage.cacheAuthorizeRequest(redirectRequest);
|
|
15245
|
+
const form = await getEARForm(document, this.config, discoveredAuthority, redirectRequest, this.logger, this.performanceClient);
|
|
15246
|
+
form.submit();
|
|
15247
|
+
}
|
|
15225
15248
|
/**
|
|
15226
15249
|
* Checks if navigateToLoginRequestUrl is set, and:
|
|
15227
15250
|
* - if true, performs logic to cache and navigate
|
|
@@ -15229,18 +15252,14 @@
|
|
|
15229
15252
|
* @param hash {string} url hash
|
|
15230
15253
|
* @param parentMeasurement {InProgressPerformanceEvent} parent measurement
|
|
15231
15254
|
*/
|
|
15232
|
-
async handleRedirectPromise(hash = "", parentMeasurement) {
|
|
15255
|
+
async handleRedirectPromise(hash = "", request, pkceVerifier, parentMeasurement) {
|
|
15233
15256
|
const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.handleRedirectPromise);
|
|
15234
15257
|
try {
|
|
15235
|
-
if (!this.browserStorage.isInteractionInProgress(true)) {
|
|
15236
|
-
this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
|
|
15237
|
-
return null;
|
|
15238
|
-
}
|
|
15239
15258
|
const [serverParams, responseString] = this.getRedirectResponse(hash || "");
|
|
15240
15259
|
if (!serverParams) {
|
|
15241
15260
|
// Not a recognized server response hash or hash not associated with a redirect request
|
|
15242
15261
|
this.logger.info("handleRedirectPromise did not detect a response as a result of a redirect. Cleaning temporary cache.");
|
|
15243
|
-
this.browserStorage.
|
|
15262
|
+
this.browserStorage.resetRequestCache();
|
|
15244
15263
|
// Do not instrument "no_server_response" if user clicked back button
|
|
15245
15264
|
if (getNavigationType() !== "back_forward") {
|
|
15246
15265
|
parentMeasurement.event.errorCode = "no_server_response";
|
|
@@ -15262,12 +15281,12 @@
|
|
|
15262
15281
|
// Replace current hash with non-msal hash, if present
|
|
15263
15282
|
replaceHash(loginRequestUrl);
|
|
15264
15283
|
}
|
|
15265
|
-
const handleHashResult = await this.handleResponse(serverParams, serverTelemetryManager);
|
|
15284
|
+
const handleHashResult = await this.handleResponse(serverParams, request, pkceVerifier, serverTelemetryManager);
|
|
15266
15285
|
return handleHashResult;
|
|
15267
15286
|
}
|
|
15268
15287
|
else if (!this.config.auth.navigateToLoginRequestUrl) {
|
|
15269
15288
|
this.logger.verbose("NavigateToLoginRequestUrl set to false, handling response");
|
|
15270
|
-
return await this.handleResponse(serverParams, serverTelemetryManager);
|
|
15289
|
+
return await this.handleResponse(serverParams, request, pkceVerifier, serverTelemetryManager);
|
|
15271
15290
|
}
|
|
15272
15291
|
else if (!isInIframe() ||
|
|
15273
15292
|
this.config.system.allowRedirectInIframe) {
|
|
@@ -15303,7 +15322,7 @@
|
|
|
15303
15322
|
}
|
|
15304
15323
|
// If navigateInternal implementation returns false, handle the hash now
|
|
15305
15324
|
if (!processHashOnRedirect) {
|
|
15306
|
-
return await this.handleResponse(serverParams, serverTelemetryManager);
|
|
15325
|
+
return await this.handleResponse(serverParams, request, pkceVerifier, serverTelemetryManager);
|
|
15307
15326
|
}
|
|
15308
15327
|
}
|
|
15309
15328
|
return null;
|
|
@@ -15313,7 +15332,6 @@
|
|
|
15313
15332
|
e.setCorrelationId(this.correlationId);
|
|
15314
15333
|
serverTelemetryManager.cacheFailedRequest(e);
|
|
15315
15334
|
}
|
|
15316
|
-
this.browserStorage.cleanRequestByInteractionType(exports.InteractionType.Redirect);
|
|
15317
15335
|
throw e;
|
|
15318
15336
|
}
|
|
15319
15337
|
}
|
|
@@ -15366,39 +15384,67 @@
|
|
|
15366
15384
|
* @param hash
|
|
15367
15385
|
* @param state
|
|
15368
15386
|
*/
|
|
15369
|
-
async handleResponse(serverParams, serverTelemetryManager) {
|
|
15387
|
+
async handleResponse(serverParams, request, codeVerifier, serverTelemetryManager) {
|
|
15370
15388
|
const state = serverParams.state;
|
|
15371
15389
|
if (!state) {
|
|
15372
15390
|
throw createBrowserAuthError(noStateInHash);
|
|
15373
15391
|
}
|
|
15374
|
-
|
|
15375
|
-
|
|
15376
|
-
|
|
15377
|
-
|
|
15378
|
-
|
|
15379
|
-
|
|
15380
|
-
}
|
|
15381
|
-
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);
|
|
15382
|
-
const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, state);
|
|
15383
|
-
return nativeInteractionClient
|
|
15384
|
-
.acquireToken({
|
|
15385
|
-
...cachedRequest,
|
|
15386
|
-
state: userRequestState,
|
|
15387
|
-
prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
|
|
15388
|
-
})
|
|
15389
|
-
.finally(() => {
|
|
15390
|
-
this.browserStorage.cleanRequestByState(state);
|
|
15392
|
+
if (serverParams.ear_jwe) {
|
|
15393
|
+
const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, request.correlationId)({
|
|
15394
|
+
requestAuthority: request.authority,
|
|
15395
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
15396
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
15397
|
+
account: request.account,
|
|
15391
15398
|
});
|
|
15399
|
+
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);
|
|
15400
|
+
}
|
|
15401
|
+
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)({ serverTelemetryManager, requestAuthority: request.authority });
|
|
15402
|
+
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);
|
|
15403
|
+
}
|
|
15404
|
+
/**
|
|
15405
|
+
* Redirects window to given URL.
|
|
15406
|
+
* @param urlNavigate
|
|
15407
|
+
* @param onRedirectNavigateRequest - onRedirectNavigate callback provided on the request
|
|
15408
|
+
*/
|
|
15409
|
+
async initiateAuthRequest(requestUrl, onRedirectNavigateRequest) {
|
|
15410
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest called");
|
|
15411
|
+
// Navigate if valid URL
|
|
15412
|
+
if (requestUrl) {
|
|
15413
|
+
this.logger.infoPii(`RedirectHandler.initiateAuthRequest: Navigate to: ${requestUrl}`);
|
|
15414
|
+
const navigationOptions = {
|
|
15415
|
+
apiId: ApiId.acquireTokenRedirect,
|
|
15416
|
+
timeout: this.config.system.redirectNavigationTimeout,
|
|
15417
|
+
noHistory: false,
|
|
15418
|
+
};
|
|
15419
|
+
const onRedirectNavigate = onRedirectNavigateRequest ||
|
|
15420
|
+
this.config.auth.onRedirectNavigate;
|
|
15421
|
+
// If onRedirectNavigate is implemented, invoke it and provide requestUrl
|
|
15422
|
+
if (typeof onRedirectNavigate === "function") {
|
|
15423
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest: Invoking onRedirectNavigate callback");
|
|
15424
|
+
const navigate = onRedirectNavigate(requestUrl);
|
|
15425
|
+
// Returning false from onRedirectNavigate will stop navigation
|
|
15426
|
+
if (navigate !== false) {
|
|
15427
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate did not return false, navigating");
|
|
15428
|
+
await this.navigationClient.navigateExternal(requestUrl, navigationOptions);
|
|
15429
|
+
return;
|
|
15430
|
+
}
|
|
15431
|
+
else {
|
|
15432
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate returned false, stopping navigation");
|
|
15433
|
+
return;
|
|
15434
|
+
}
|
|
15435
|
+
}
|
|
15436
|
+
else {
|
|
15437
|
+
// Navigate window to request URL
|
|
15438
|
+
this.logger.verbose("RedirectHandler.initiateAuthRequest: Navigating window to navigate url");
|
|
15439
|
+
await this.navigationClient.navigateExternal(requestUrl, navigationOptions);
|
|
15440
|
+
return;
|
|
15441
|
+
}
|
|
15392
15442
|
}
|
|
15393
|
-
|
|
15394
|
-
|
|
15395
|
-
|
|
15396
|
-
throw createBrowserAuthError(
|
|
15443
|
+
else {
|
|
15444
|
+
// Throw error if request URL is empty.
|
|
15445
|
+
this.logger.info("RedirectHandler.initiateAuthRequest: Navigate url is empty");
|
|
15446
|
+
throw createBrowserAuthError(emptyNavigateUri);
|
|
15397
15447
|
}
|
|
15398
|
-
const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)({ serverTelemetryManager, requestAuthority: currentAuthority });
|
|
15399
|
-
ThrottlingUtils.removeThrottle(this.browserStorage, this.config.auth.clientId, cachedRequest);
|
|
15400
|
-
const interactionHandler = new RedirectHandler(authClient, this.browserStorage, cachedRequest, this.logger, this.performanceClient);
|
|
15401
|
-
return interactionHandler.handleCodeResponse(serverParams, state);
|
|
15402
15448
|
}
|
|
15403
15449
|
/**
|
|
15404
15450
|
* Use to log out the current user, and redirect the user to the postLogoutRedirectUri.
|
|
@@ -15497,7 +15543,7 @@
|
|
|
15497
15543
|
* @param urlNavigate
|
|
15498
15544
|
* @param userRequestScopes
|
|
15499
15545
|
*/
|
|
15500
|
-
async function
|
|
15546
|
+
async function initiateCodeRequest(requestUrl, performanceClient, logger, correlationId, navigateFrameWait) {
|
|
15501
15547
|
performanceClient.addQueueMeasurement(PerformanceEvents.SilentHandlerInitiateAuthRequest, correlationId);
|
|
15502
15548
|
if (!requestUrl) {
|
|
15503
15549
|
// Throw error if request URL is empty.
|
|
@@ -15509,6 +15555,15 @@
|
|
|
15509
15555
|
}
|
|
15510
15556
|
return invoke(loadFrameSync, PerformanceEvents.SilentHandlerLoadFrameSync, logger, performanceClient, correlationId)(requestUrl);
|
|
15511
15557
|
}
|
|
15558
|
+
async function initiateEarRequest(config, authority, request, logger, performanceClient) {
|
|
15559
|
+
const frame = createHiddenIframe();
|
|
15560
|
+
if (!frame.contentDocument) {
|
|
15561
|
+
throw "No document associated with iframe!";
|
|
15562
|
+
}
|
|
15563
|
+
const form = await getEARForm(frame.contentDocument, config, authority, request, logger, performanceClient);
|
|
15564
|
+
form.submit();
|
|
15565
|
+
return frame;
|
|
15566
|
+
}
|
|
15512
15567
|
/**
|
|
15513
15568
|
* Monitors an iframe content window until it loads a url with a known hash, or hits a specified timeout.
|
|
15514
15569
|
* @param iframe
|
|
@@ -15659,19 +15714,34 @@
|
|
|
15659
15714
|
}
|
|
15660
15715
|
// Create silent request
|
|
15661
15716
|
const silentRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, request.correlationId)(inputRequest, exports.InteractionType.Silent);
|
|
15717
|
+
silentRequest.platformBroker =
|
|
15718
|
+
NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, silentRequest.authenticationScheme);
|
|
15662
15719
|
preconnect(silentRequest.authority);
|
|
15663
|
-
|
|
15720
|
+
if (this.config.auth.protocolMode === ProtocolMode.EAR) {
|
|
15721
|
+
return this.executeEarFlow(silentRequest);
|
|
15722
|
+
}
|
|
15723
|
+
else {
|
|
15724
|
+
return this.executeCodeFlow(silentRequest);
|
|
15725
|
+
}
|
|
15726
|
+
}
|
|
15727
|
+
/**
|
|
15728
|
+
* Executes auth code + PKCE flow
|
|
15729
|
+
* @param request
|
|
15730
|
+
* @returns
|
|
15731
|
+
*/
|
|
15732
|
+
async executeCodeFlow(request) {
|
|
15664
15733
|
let authClient;
|
|
15734
|
+
const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
|
|
15665
15735
|
try {
|
|
15666
15736
|
// Initialize the client
|
|
15667
15737
|
authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, request.correlationId)({
|
|
15668
15738
|
serverTelemetryManager,
|
|
15669
|
-
requestAuthority:
|
|
15670
|
-
requestAzureCloudOptions:
|
|
15671
|
-
requestExtraQueryParameters:
|
|
15672
|
-
account:
|
|
15739
|
+
requestAuthority: request.authority,
|
|
15740
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
15741
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
15742
|
+
account: request.account,
|
|
15673
15743
|
});
|
|
15674
|
-
return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, request.correlationId)(authClient,
|
|
15744
|
+
return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, request.correlationId)(authClient, request);
|
|
15675
15745
|
}
|
|
15676
15746
|
catch (e) {
|
|
15677
15747
|
if (e instanceof AuthError) {
|
|
@@ -15686,10 +15756,33 @@
|
|
|
15686
15756
|
this.performanceClient.addFields({
|
|
15687
15757
|
retryError: e.errorCode,
|
|
15688
15758
|
}, this.correlationId);
|
|
15689
|
-
|
|
15690
|
-
return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, this.correlationId)(authClient, retrySilentRequest);
|
|
15759
|
+
return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, this.correlationId)(authClient, request);
|
|
15691
15760
|
}
|
|
15692
15761
|
}
|
|
15762
|
+
/**
|
|
15763
|
+
* Executes EAR flow
|
|
15764
|
+
* @param request
|
|
15765
|
+
*/
|
|
15766
|
+
async executeEarFlow(request) {
|
|
15767
|
+
const correlationId = request.correlationId;
|
|
15768
|
+
const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, correlationId)({
|
|
15769
|
+
requestAuthority: request.authority,
|
|
15770
|
+
requestAzureCloudOptions: request.azureCloudOptions,
|
|
15771
|
+
requestExtraQueryParameters: request.extraQueryParameters,
|
|
15772
|
+
account: request.account,
|
|
15773
|
+
});
|
|
15774
|
+
const earJwk = await invokeAsync(generateEarKey, PerformanceEvents.GenerateEarKey, this.logger, this.performanceClient, correlationId)();
|
|
15775
|
+
const silentRequest = {
|
|
15776
|
+
...request,
|
|
15777
|
+
earJwk: earJwk,
|
|
15778
|
+
};
|
|
15779
|
+
const msalFrame = await invokeAsync(initiateEarRequest, PerformanceEvents.SilentHandlerInitiateAuthRequest, this.logger, this.performanceClient, correlationId)(this.config, discoveredAuthority, silentRequest, this.logger, this.performanceClient);
|
|
15780
|
+
const responseType = this.config.auth.OIDCOptions.serverResponseType;
|
|
15781
|
+
// Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
|
|
15782
|
+
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);
|
|
15783
|
+
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, correlationId)(responseString, responseType, this.logger);
|
|
15784
|
+
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);
|
|
15785
|
+
}
|
|
15693
15786
|
/**
|
|
15694
15787
|
* Currently Unsupported
|
|
15695
15788
|
*/
|
|
@@ -15706,44 +15799,20 @@
|
|
|
15706
15799
|
async silentTokenHelper(authClient, request) {
|
|
15707
15800
|
const correlationId = request.correlationId;
|
|
15708
15801
|
this.performanceClient.addQueueMeasurement(PerformanceEvents.SilentIframeClientTokenHelper, correlationId);
|
|
15709
|
-
const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient,
|
|
15802
|
+
const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, correlationId)(this.performanceClient, this.logger, correlationId);
|
|
15710
15803
|
const silentRequest = {
|
|
15711
15804
|
...request,
|
|
15712
15805
|
codeChallenge: pkceCodes.challenge,
|
|
15713
15806
|
};
|
|
15714
15807
|
// Create authorize request url
|
|
15715
|
-
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, correlationId)(this.config, authClient.authority,
|
|
15716
|
-
...silentRequest,
|
|
15717
|
-
platformBroker: NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, silentRequest.authenticationScheme),
|
|
15718
|
-
}, this.logger, this.performanceClient);
|
|
15808
|
+
const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, correlationId)(this.config, authClient.authority, silentRequest, this.logger, this.performanceClient);
|
|
15719
15809
|
// Get the frame handle for the silent request
|
|
15720
|
-
const msalFrame = await invokeAsync(
|
|
15810
|
+
const msalFrame = await invokeAsync(initiateCodeRequest, PerformanceEvents.SilentHandlerInitiateAuthRequest, this.logger, this.performanceClient, correlationId)(navigateUrl, this.performanceClient, this.logger, correlationId, this.config.system.navigateFrameWait);
|
|
15721
15811
|
const responseType = this.config.auth.OIDCOptions.serverResponseType;
|
|
15722
15812
|
// Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
|
|
15723
15813
|
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);
|
|
15724
|
-
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient,
|
|
15725
|
-
|
|
15726
|
-
this.logger.verbose("Account id found in hash, calling WAM for token");
|
|
15727
|
-
if (!this.nativeMessageHandler) {
|
|
15728
|
-
throw createBrowserAuthError(nativeConnectionNotEstablished);
|
|
15729
|
-
}
|
|
15730
|
-
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);
|
|
15731
|
-
const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, silentRequest.state);
|
|
15732
|
-
return invokeAsync(nativeInteractionClient.acquireToken.bind(nativeInteractionClient), PerformanceEvents.NativeInteractionClientAcquireToken, this.logger, this.performanceClient, correlationId)({
|
|
15733
|
-
...silentRequest,
|
|
15734
|
-
state: userRequestState,
|
|
15735
|
-
prompt: silentRequest.prompt || PromptValue.NONE,
|
|
15736
|
-
});
|
|
15737
|
-
}
|
|
15738
|
-
const authCodeRequest = {
|
|
15739
|
-
...silentRequest,
|
|
15740
|
-
code: serverParams.code || "",
|
|
15741
|
-
codeVerifier: pkceCodes.verifier,
|
|
15742
|
-
};
|
|
15743
|
-
// Create silent handler
|
|
15744
|
-
const interactionHandler = new InteractionHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.performanceClient);
|
|
15745
|
-
// Handle response from hash string
|
|
15746
|
-
return invokeAsync(interactionHandler.handleCodeResponse.bind(interactionHandler), PerformanceEvents.HandleCodeResponse, this.logger, this.performanceClient, correlationId)(serverParams, silentRequest);
|
|
15814
|
+
const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, correlationId)(responseString, responseType, this.logger);
|
|
15815
|
+
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);
|
|
15747
15816
|
}
|
|
15748
15817
|
}
|
|
15749
15818
|
|
|
@@ -16272,31 +16341,38 @@
|
|
|
16272
16341
|
* @returns
|
|
16273
16342
|
*/
|
|
16274
16343
|
async handleRedirectPromiseInternal(hash) {
|
|
16344
|
+
if (!this.browserStorage.isInteractionInProgress(true)) {
|
|
16345
|
+
this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
|
|
16346
|
+
return null;
|
|
16347
|
+
}
|
|
16275
16348
|
const loggedInAccounts = this.getAllAccounts();
|
|
16276
|
-
const
|
|
16277
|
-
const useNative =
|
|
16349
|
+
const platformBrokerRequest = this.browserStorage.getCachedNativeRequest();
|
|
16350
|
+
const useNative = platformBrokerRequest &&
|
|
16278
16351
|
NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeExtensionProvider) &&
|
|
16279
16352
|
this.nativeExtensionProvider &&
|
|
16280
16353
|
!hash;
|
|
16281
|
-
|
|
16282
|
-
? request?.correlationId
|
|
16283
|
-
: this.browserStorage.getTemporaryCache(TemporaryCacheKeys.CORRELATION_ID, true) || "";
|
|
16284
|
-
const rootMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenRedirect, correlationId);
|
|
16354
|
+
let rootMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenRedirect, platformBrokerRequest?.correlationId || "");
|
|
16285
16355
|
this.eventHandler.emitEvent(EventType.HANDLE_REDIRECT_START, exports.InteractionType.Redirect);
|
|
16286
16356
|
let redirectResponse;
|
|
16287
16357
|
if (useNative && this.nativeExtensionProvider) {
|
|
16288
16358
|
this.logger.trace("handleRedirectPromise - acquiring token from native platform");
|
|
16289
|
-
const nativeClient = new NativeInteractionClient(this.config, this.browserStorage, this.browserCrypto, this.logger, this.eventHandler, this.navigationClient, ApiId.handleRedirectPromise, this.performanceClient, this.nativeExtensionProvider,
|
|
16359
|
+
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);
|
|
16290
16360
|
redirectResponse = invokeAsync(nativeClient.handleRedirectPromise.bind(nativeClient), PerformanceEvents.HandleNativeRedirectPromiseMeasurement, this.logger, this.performanceClient, rootMeasurement.event.correlationId)(this.performanceClient, rootMeasurement.event.correlationId);
|
|
16291
16361
|
}
|
|
16292
16362
|
else {
|
|
16363
|
+
const [standardRequest, codeVerifier] = this.browserStorage.getCachedRequest();
|
|
16364
|
+
const correlationId = standardRequest.correlationId;
|
|
16365
|
+
// Reset rootMeasurement now that we have correlationId
|
|
16366
|
+
rootMeasurement.discard();
|
|
16367
|
+
rootMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenRedirect, correlationId);
|
|
16293
16368
|
this.logger.trace("handleRedirectPromise - acquiring token from web flow");
|
|
16294
16369
|
const redirectClient = this.createRedirectClient(correlationId);
|
|
16295
|
-
redirectResponse = invokeAsync(redirectClient.handleRedirectPromise.bind(redirectClient), PerformanceEvents.HandleRedirectPromiseMeasurement, this.logger, this.performanceClient, rootMeasurement.event.correlationId)(hash, rootMeasurement);
|
|
16370
|
+
redirectResponse = invokeAsync(redirectClient.handleRedirectPromise.bind(redirectClient), PerformanceEvents.HandleRedirectPromiseMeasurement, this.logger, this.performanceClient, rootMeasurement.event.correlationId)(hash, standardRequest, codeVerifier, rootMeasurement);
|
|
16296
16371
|
}
|
|
16297
16372
|
return redirectResponse
|
|
16298
16373
|
.then((result) => {
|
|
16299
16374
|
if (result) {
|
|
16375
|
+
this.browserStorage.resetRequestCache();
|
|
16300
16376
|
// Emit login event if number of accounts change
|
|
16301
16377
|
const isLoggingIn = loggedInAccounts.length < this.getAllAccounts().length;
|
|
16302
16378
|
if (isLoggingIn) {
|
|
@@ -16328,6 +16404,7 @@
|
|
|
16328
16404
|
return result;
|
|
16329
16405
|
})
|
|
16330
16406
|
.catch((e) => {
|
|
16407
|
+
this.browserStorage.resetRequestCache();
|
|
16331
16408
|
const eventError = e;
|
|
16332
16409
|
// Emit login event if there is an account
|
|
16333
16410
|
if (loggedInAccounts.length > 0) {
|
|
@@ -16421,7 +16498,6 @@
|
|
|
16421
16498
|
const redirectClient = this.createRedirectClient(correlationId);
|
|
16422
16499
|
return redirectClient.acquireToken(request);
|
|
16423
16500
|
}
|
|
16424
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
16425
16501
|
throw e;
|
|
16426
16502
|
});
|
|
16427
16503
|
}
|
|
@@ -16432,6 +16508,7 @@
|
|
|
16432
16508
|
return await result;
|
|
16433
16509
|
}
|
|
16434
16510
|
catch (e) {
|
|
16511
|
+
this.browserStorage.resetRequestCache();
|
|
16435
16512
|
atrMeasurement.end({ success: false }, e);
|
|
16436
16513
|
if (isLoggedIn) {
|
|
16437
16514
|
this.eventHandler.emitEvent(EventType.ACQUIRE_TOKEN_FAILURE, exports.InteractionType.Redirect, null, e);
|
|
@@ -16483,7 +16560,6 @@
|
|
|
16483
16560
|
correlationId,
|
|
16484
16561
|
}, ApiId.acquireTokenPopup)
|
|
16485
16562
|
.then((response) => {
|
|
16486
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
16487
16563
|
atPopupMeasurement.end({
|
|
16488
16564
|
success: true,
|
|
16489
16565
|
isNativeBroker: true,
|
|
@@ -16503,7 +16579,6 @@
|
|
|
16503
16579
|
const popupClient = this.createPopupClient(correlationId);
|
|
16504
16580
|
return popupClient.acquireToken(request, pkce);
|
|
16505
16581
|
}
|
|
16506
|
-
this.browserStorage.setInteractionInProgress(false);
|
|
16507
16582
|
throw e;
|
|
16508
16583
|
});
|
|
16509
16584
|
}
|
|
@@ -16544,8 +16619,12 @@
|
|
|
16544
16619
|
// Since this function is syncronous we need to reject
|
|
16545
16620
|
return Promise.reject(e);
|
|
16546
16621
|
})
|
|
16547
|
-
.finally(() =>
|
|
16548
|
-
this.
|
|
16622
|
+
.finally(async () => {
|
|
16623
|
+
this.browserStorage.setInteractionInProgress(false);
|
|
16624
|
+
if (this.config.system.asyncPopups) {
|
|
16625
|
+
await this.preGeneratePkceCodes(correlationId);
|
|
16626
|
+
}
|
|
16627
|
+
});
|
|
16549
16628
|
}
|
|
16550
16629
|
trackPageVisibilityWithMeasurement() {
|
|
16551
16630
|
const measurement = this.ssoSilentMeasurement ||
|
|
@@ -16848,7 +16927,9 @@
|
|
|
16848
16927
|
preflightCheck$1(this.initialized);
|
|
16849
16928
|
this.browserStorage.setInteractionInProgress(true);
|
|
16850
16929
|
const popupClient = this.createPopupClient(correlationId);
|
|
16851
|
-
return popupClient.logout(logoutRequest)
|
|
16930
|
+
return popupClient.logout(logoutRequest).finally(() => {
|
|
16931
|
+
this.browserStorage.setInteractionInProgress(false);
|
|
16932
|
+
});
|
|
16852
16933
|
}
|
|
16853
16934
|
catch (e) {
|
|
16854
16935
|
// Since this function is syncronous we need to reject
|