@azure/msal-common 14.1.0-alpha.0 → 14.1.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.
Files changed (205) hide show
  1. package/dist/account/AccountInfo.d.ts +31 -32
  2. package/dist/account/AccountInfo.d.ts.map +1 -1
  3. package/dist/account/AuthToken.d.ts +17 -17
  4. package/dist/account/AuthToken.mjs +58 -58
  5. package/dist/account/CcsCredential.d.ts +9 -9
  6. package/dist/account/CcsCredential.mjs +8 -8
  7. package/dist/account/ClientCredentials.d.ts +14 -14
  8. package/dist/account/ClientInfo.d.ts +19 -19
  9. package/dist/account/ClientInfo.mjs +37 -37
  10. package/dist/account/TokenClaims.d.ts +65 -65
  11. package/dist/authority/Authority.d.ts +235 -235
  12. package/dist/authority/Authority.mjs +738 -738
  13. package/dist/authority/AuthorityFactory.d.ts +31 -31
  14. package/dist/authority/AuthorityFactory.mjs +47 -47
  15. package/dist/authority/AuthorityMetadata.d.ts +623 -623
  16. package/dist/authority/AuthorityMetadata.mjs +884 -884
  17. package/dist/authority/AuthorityOptions.d.ts +21 -21
  18. package/dist/authority/AuthorityOptions.mjs +18 -18
  19. package/dist/authority/AuthorityType.d.ts +10 -10
  20. package/dist/authority/AuthorityType.mjs +13 -13
  21. package/dist/authority/AzureRegion.d.ts +1 -1
  22. package/dist/authority/AzureRegionConfiguration.d.ts +5 -5
  23. package/dist/authority/CloudDiscoveryMetadata.d.ts +5 -5
  24. package/dist/authority/CloudInstanceDiscoveryErrorResponse.d.ts +13 -13
  25. package/dist/authority/CloudInstanceDiscoveryErrorResponse.mjs +8 -8
  26. package/dist/authority/CloudInstanceDiscoveryResponse.d.ts +9 -9
  27. package/dist/authority/CloudInstanceDiscoveryResponse.mjs +8 -8
  28. package/dist/authority/ImdsOptions.d.ts +5 -5
  29. package/dist/authority/OIDCOptions.d.ts +8 -8
  30. package/dist/authority/OpenIdConfigResponse.d.ts +11 -11
  31. package/dist/authority/OpenIdConfigResponse.mjs +10 -10
  32. package/dist/authority/ProtocolMode.d.ts +8 -8
  33. package/dist/authority/ProtocolMode.mjs +11 -11
  34. package/dist/authority/RegionDiscovery.d.ts +32 -32
  35. package/dist/authority/RegionDiscovery.mjs +106 -106
  36. package/dist/authority/RegionDiscoveryMetadata.d.ts +6 -6
  37. package/dist/broker/nativeBroker/INativeBrokerPlugin.d.ts +15 -15
  38. package/dist/cache/CacheManager.d.ts +464 -446
  39. package/dist/cache/CacheManager.d.ts.map +1 -1
  40. package/dist/cache/CacheManager.mjs +1049 -998
  41. package/dist/cache/CacheManager.mjs.map +1 -1
  42. package/dist/cache/entities/AccessTokenEntity.d.ts +56 -56
  43. package/dist/cache/entities/AccessTokenEntity.mjs +109 -109
  44. package/dist/cache/entities/AccountEntity.d.ts +101 -101
  45. package/dist/cache/entities/AccountEntity.mjs +220 -220
  46. package/dist/cache/entities/AppMetadataEntity.d.ts +39 -39
  47. package/dist/cache/entities/AppMetadataEntity.mjs +66 -66
  48. package/dist/cache/entities/AuthorityMetadataEntity.d.ts +48 -48
  49. package/dist/cache/entities/AuthorityMetadataEntity.mjs +78 -78
  50. package/dist/cache/entities/CacheRecord.d.ts +14 -14
  51. package/dist/cache/entities/CacheRecord.mjs +14 -14
  52. package/dist/cache/entities/CredentialEntity.d.ts +88 -88
  53. package/dist/cache/entities/CredentialEntity.mjs +136 -136
  54. package/dist/cache/entities/IdTokenEntity.d.ts +34 -34
  55. package/dist/cache/entities/IdTokenEntity.mjs +56 -56
  56. package/dist/cache/entities/RefreshTokenEntity.d.ts +36 -36
  57. package/dist/cache/entities/RefreshTokenEntity.mjs +59 -59
  58. package/dist/cache/entities/ServerTelemetryEntity.d.ts +12 -12
  59. package/dist/cache/entities/ServerTelemetryEntity.mjs +27 -27
  60. package/dist/cache/entities/ThrottlingEntity.d.ts +13 -13
  61. package/dist/cache/entities/ThrottlingEntity.mjs +23 -23
  62. package/dist/cache/interface/ICacheManager.d.ts +166 -166
  63. package/dist/cache/interface/ICachePlugin.d.ts +5 -5
  64. package/dist/cache/interface/ISerializableTokenCache.d.ts +4 -4
  65. package/dist/cache/persistence/TokenCacheContext.d.ts +23 -23
  66. package/dist/cache/persistence/TokenCacheContext.mjs +25 -25
  67. package/dist/cache/utils/CacheTypes.d.ts +66 -69
  68. package/dist/cache/utils/CacheTypes.d.ts.map +1 -1
  69. package/dist/client/AuthorizationCodeClient.d.ts +73 -73
  70. package/dist/client/AuthorizationCodeClient.d.ts.map +1 -1
  71. package/dist/client/AuthorizationCodeClient.mjs +408 -407
  72. package/dist/client/AuthorizationCodeClient.mjs.map +1 -1
  73. package/dist/client/BaseClient.d.ts +51 -51
  74. package/dist/client/BaseClient.mjs +98 -98
  75. package/dist/client/RefreshTokenClient.d.ts +35 -35
  76. package/dist/client/RefreshTokenClient.d.ts.map +1 -1
  77. package/dist/client/RefreshTokenClient.mjs +187 -179
  78. package/dist/client/RefreshTokenClient.mjs.map +1 -1
  79. package/dist/client/SilentFlowClient.d.ts +26 -26
  80. package/dist/client/SilentFlowClient.mjs +123 -123
  81. package/dist/config/AppTokenProvider.d.ts +38 -38
  82. package/dist/config/ClientConfiguration.d.ts +150 -150
  83. package/dist/config/ClientConfiguration.mjs +97 -97
  84. package/dist/crypto/ICrypto.d.ts +58 -62
  85. package/dist/crypto/ICrypto.d.ts.map +1 -1
  86. package/dist/crypto/ICrypto.mjs +30 -33
  87. package/dist/crypto/ICrypto.mjs.map +1 -1
  88. package/dist/crypto/IGuidGenerator.d.ts +4 -4
  89. package/dist/crypto/JoseHeader.d.ts +22 -22
  90. package/dist/crypto/JoseHeader.mjs +37 -37
  91. package/dist/crypto/PopTokenGenerator.d.ts +60 -60
  92. package/dist/crypto/PopTokenGenerator.mjs +82 -82
  93. package/dist/crypto/SignedHttpRequest.d.ts +11 -11
  94. package/dist/error/AuthError.d.ts +44 -44
  95. package/dist/error/AuthError.mjs +46 -46
  96. package/dist/error/AuthErrorCodes.d.ts +5 -5
  97. package/dist/error/AuthErrorCodes.mjs +9 -9
  98. package/dist/error/ClientAuthError.d.ts +232 -232
  99. package/dist/error/ClientAuthError.mjs +244 -244
  100. package/dist/error/ClientAuthErrorCodes.d.ts +43 -43
  101. package/dist/error/ClientAuthErrorCodes.mjs +47 -47
  102. package/dist/error/ClientConfigurationError.d.ts +128 -128
  103. package/dist/error/ClientConfigurationError.mjs +135 -135
  104. package/dist/error/ClientConfigurationErrorCodes.d.ts +22 -22
  105. package/dist/error/ClientConfigurationErrorCodes.mjs +26 -26
  106. package/dist/error/InteractionRequiredAuthError.d.ts +57 -57
  107. package/dist/error/InteractionRequiredAuthError.mjs +76 -76
  108. package/dist/error/InteractionRequiredAuthErrorCodes.d.ts +5 -5
  109. package/dist/error/InteractionRequiredAuthErrorCodes.mjs +11 -11
  110. package/dist/error/JoseHeaderError.d.ts +15 -15
  111. package/dist/error/JoseHeaderError.mjs +22 -22
  112. package/dist/error/JoseHeaderErrorCodes.d.ts +2 -2
  113. package/dist/error/JoseHeaderErrorCodes.mjs +6 -6
  114. package/dist/error/ServerError.d.ts +7 -7
  115. package/dist/error/ServerError.mjs +14 -14
  116. package/dist/index.cjs +8672 -8608
  117. package/dist/index.cjs.map +1 -1
  118. package/dist/index.d.ts +96 -96
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.mjs +1 -1
  121. package/dist/logger/Logger.d.ts +95 -95
  122. package/dist/logger/Logger.mjs +188 -188
  123. package/dist/network/INetworkModule.d.ts +29 -29
  124. package/dist/network/INetworkModule.mjs +12 -12
  125. package/dist/network/NetworkManager.d.ts +33 -33
  126. package/dist/network/NetworkManager.mjs +34 -34
  127. package/dist/network/RequestThumbprint.d.ts +16 -16
  128. package/dist/network/ThrottlingUtils.d.ts +42 -42
  129. package/dist/network/ThrottlingUtils.mjs +95 -95
  130. package/dist/packageMetadata.d.ts +2 -2
  131. package/dist/packageMetadata.mjs +4 -4
  132. package/dist/request/AuthenticationHeaderParser.d.ts +19 -19
  133. package/dist/request/AuthenticationHeaderParser.mjs +55 -55
  134. package/dist/request/BaseAuthRequest.d.ts +40 -40
  135. package/dist/request/CommonAuthorizationCodeRequest.d.ts +27 -27
  136. package/dist/request/CommonAuthorizationUrlRequest.d.ts +50 -50
  137. package/dist/request/CommonClientCredentialRequest.d.ts +17 -17
  138. package/dist/request/CommonDeviceCodeRequest.d.ts +21 -21
  139. package/dist/request/CommonEndSessionRequest.d.ts +21 -21
  140. package/dist/request/CommonOnBehalfOfRequest.d.ts +13 -13
  141. package/dist/request/CommonRefreshTokenRequest.d.ts +22 -19
  142. package/dist/request/CommonRefreshTokenRequest.d.ts.map +1 -1
  143. package/dist/request/CommonSilentFlowRequest.d.ts +20 -18
  144. package/dist/request/CommonSilentFlowRequest.d.ts.map +1 -1
  145. package/dist/request/CommonUsernamePasswordRequest.d.ts +17 -17
  146. package/dist/request/NativeRequest.d.ts +19 -19
  147. package/dist/request/NativeSignOutRequest.d.ts +5 -5
  148. package/dist/request/RequestParameterBuilder.d.ts +217 -217
  149. package/dist/request/RequestParameterBuilder.mjs +381 -381
  150. package/dist/request/RequestValidator.d.ts +33 -33
  151. package/dist/request/RequestValidator.mjs +81 -81
  152. package/dist/request/ScopeSet.d.ts +88 -88
  153. package/dist/request/ScopeSet.mjs +197 -197
  154. package/dist/request/StoreInCache.d.ts +8 -8
  155. package/dist/response/AuthenticationResult.d.ts +41 -41
  156. package/dist/response/AuthorizationCodePayload.d.ts +13 -13
  157. package/dist/response/DeviceCodeResponse.d.ts +25 -25
  158. package/dist/response/ExternalTokenResponse.d.ts +15 -15
  159. package/dist/response/IMDSBadResponse.d.ts +4 -4
  160. package/dist/response/ResponseHandler.d.ts +67 -67
  161. package/dist/response/ResponseHandler.mjs +311 -311
  162. package/dist/response/ServerAuthorizationCodeResponse.d.ts +25 -25
  163. package/dist/response/ServerAuthorizationTokenResponse.d.ts +46 -46
  164. package/dist/telemetry/performance/IPerformanceClient.d.ts +51 -51
  165. package/dist/telemetry/performance/IPerformanceMeasurement.d.ts +5 -5
  166. package/dist/telemetry/performance/PerformanceClient.d.ts +191 -191
  167. package/dist/telemetry/performance/PerformanceClient.mjs +409 -409
  168. package/dist/telemetry/performance/PerformanceEvent.d.ts +441 -433
  169. package/dist/telemetry/performance/PerformanceEvent.d.ts.map +1 -1
  170. package/dist/telemetry/performance/PerformanceEvent.mjs +242 -234
  171. package/dist/telemetry/performance/PerformanceEvent.mjs.map +1 -1
  172. package/dist/telemetry/performance/StubPerformanceClient.d.ts +24 -24
  173. package/dist/telemetry/performance/StubPerformanceClient.mjs +76 -76
  174. package/dist/telemetry/server/ServerTelemetryManager.d.ts +66 -66
  175. package/dist/telemetry/server/ServerTelemetryManager.mjs +197 -197
  176. package/dist/telemetry/server/ServerTelemetryRequest.d.ts +8 -8
  177. package/dist/url/IUri.d.ts +12 -12
  178. package/dist/url/UrlString.d.ts +83 -83
  179. package/dist/url/UrlString.mjs +279 -279
  180. package/dist/utils/Constants.d.ts +366 -366
  181. package/dist/utils/Constants.mjs +376 -376
  182. package/dist/utils/FunctionWrappers.d.ts +27 -27
  183. package/dist/utils/FunctionWrappers.d.ts.map +1 -1
  184. package/dist/utils/FunctionWrappers.mjs +84 -85
  185. package/dist/utils/FunctionWrappers.mjs.map +1 -1
  186. package/dist/utils/MsalTypes.d.ts +6 -6
  187. package/dist/utils/ProtocolUtils.d.ts +42 -42
  188. package/dist/utils/ProtocolUtils.mjs +69 -69
  189. package/dist/utils/StringUtils.d.ts +40 -40
  190. package/dist/utils/StringUtils.mjs +95 -95
  191. package/dist/utils/TimeUtils.d.ts +27 -27
  192. package/dist/utils/TimeUtils.mjs +45 -45
  193. package/package.json +1 -1
  194. package/src/account/AccountInfo.ts +0 -1
  195. package/src/cache/CacheManager.ts +96 -18
  196. package/src/cache/utils/CacheTypes.ts +6 -6
  197. package/src/client/AuthorizationCodeClient.ts +3 -1
  198. package/src/client/RefreshTokenClient.ts +19 -2
  199. package/src/crypto/ICrypto.ts +0 -7
  200. package/src/index.ts +1 -0
  201. package/src/packageMetadata.ts +1 -1
  202. package/src/request/CommonRefreshTokenRequest.ts +3 -0
  203. package/src/request/CommonSilentFlowRequest.ts +2 -0
  204. package/src/telemetry/performance/PerformanceEvent.ts +9 -0
  205. package/src/utils/FunctionWrappers.ts +0 -1
@@ -1,4 +1,4 @@
1
- /*! @azure/msal-common v14.1.0-alpha.0 2023-09-20 */
1
+ /*! @azure/msal-common v14.1.0 2023-10-05 */
2
2
  'use strict';
3
3
  import { Separators, CredentialType, AuthenticationScheme, THE_FAMILY_ID, APP_METADATA, AUTHORITY_METADATA_CONSTANTS } from '../utils/Constants.mjs';
4
4
  import { ScopeSet } from '../request/ScopeSet.mjs';
@@ -8,1003 +8,1054 @@ import { extractTokenClaims } from '../account/AuthToken.mjs';
8
8
  import { name, version } from '../packageMetadata.mjs';
9
9
  import { invalidCacheRecord, bindingKeyNotRemoved, multipleMatchingAppMetadata, methodNotImplemented } from '../error/ClientAuthErrorCodes.mjs';
10
10
 
11
- /*
12
- * Copyright (c) Microsoft Corporation. All rights reserved.
13
- * Licensed under the MIT License.
14
- */
15
- /**
16
- * Interface class which implement cache storage functions used by MSAL to perform validity checks, and store tokens.
17
- * @internal
18
- */
19
- class CacheManager {
20
- constructor(clientId, cryptoImpl, logger) {
21
- this.clientId = clientId;
22
- this.cryptoImpl = cryptoImpl;
23
- this.commonLogger = logger.clone(name, version);
24
- }
25
- /**
26
- * Returns all accounts in cache
27
- */
28
- getAllAccounts() {
29
- const allAccountKeys = this.getAccountKeys();
30
- if (allAccountKeys.length < 1) {
31
- return [];
32
- }
33
- const accountEntities = allAccountKeys.reduce((accounts, key) => {
34
- const entity = this.getAccount(key);
35
- if (!entity) {
36
- return accounts;
37
- }
38
- accounts.push(entity);
39
- return accounts;
40
- }, []);
41
- if (accountEntities.length < 1) {
42
- return [];
43
- }
44
- else {
45
- const allAccounts = accountEntities.map((accountEntity) => {
46
- return this.getAccountInfoFromEntity(accountEntity);
47
- });
48
- return allAccounts;
49
- }
50
- }
51
- /**
52
- * Gets accountInfo object based on provided filters
53
- */
54
- getAccountInfoFilteredBy(accountFilter) {
55
- const allAccounts = this.getAccountsFilteredBy(accountFilter);
56
- if (allAccounts.length > 0) {
57
- return this.getAccountInfoFromEntity(allAccounts[0]);
58
- }
59
- else {
60
- return null;
61
- }
62
- }
63
- getAccountInfoFromEntity(accountEntity) {
64
- const accountInfo = accountEntity.getAccountInfo();
65
- const idToken = this.getIdToken(accountInfo);
66
- if (idToken) {
67
- accountInfo.idToken = idToken.secret;
68
- accountInfo.idTokenClaims = extractTokenClaims(idToken.secret, this.cryptoImpl.base64Decode);
69
- }
70
- return accountInfo;
71
- }
72
- /**
73
- * saves a cache record
74
- * @param cacheRecord
75
- */
76
- async saveCacheRecord(cacheRecord, storeInCache) {
77
- if (!cacheRecord) {
78
- throw createClientAuthError(invalidCacheRecord);
79
- }
80
- if (!!cacheRecord.account) {
81
- this.setAccount(cacheRecord.account);
82
- }
83
- if (!!cacheRecord.idToken && storeInCache?.idToken !== false) {
84
- this.setIdTokenCredential(cacheRecord.idToken);
85
- }
86
- if (!!cacheRecord.accessToken && storeInCache?.accessToken !== false) {
87
- await this.saveAccessToken(cacheRecord.accessToken);
88
- }
89
- if (!!cacheRecord.refreshToken &&
90
- storeInCache?.refreshToken !== false) {
91
- this.setRefreshTokenCredential(cacheRecord.refreshToken);
92
- }
93
- if (!!cacheRecord.appMetadata) {
94
- this.setAppMetadata(cacheRecord.appMetadata);
95
- }
96
- }
97
- /**
98
- * saves access token credential
99
- * @param credential
100
- */
101
- async saveAccessToken(credential) {
102
- const accessTokenFilter = {
103
- clientId: credential.clientId,
104
- credentialType: credential.credentialType,
105
- environment: credential.environment,
106
- homeAccountId: credential.homeAccountId,
107
- realm: credential.realm,
108
- tokenType: credential.tokenType,
109
- requestedClaimsHash: credential.requestedClaimsHash,
110
- };
111
- const tokenKeys = this.getTokenKeys();
112
- const currentScopes = ScopeSet.fromString(credential.target);
113
- const removedAccessTokens = [];
114
- tokenKeys.accessToken.forEach((key) => {
115
- if (!this.accessTokenKeyMatchesFilter(key, accessTokenFilter, false)) {
116
- return;
117
- }
118
- const tokenEntity = this.getAccessTokenCredential(key);
119
- if (tokenEntity &&
120
- this.credentialMatchesFilter(tokenEntity, accessTokenFilter)) {
121
- const tokenScopeSet = ScopeSet.fromString(tokenEntity.target);
122
- if (tokenScopeSet.intersectingScopeSets(currentScopes)) {
123
- removedAccessTokens.push(this.removeAccessToken(key));
124
- }
125
- }
126
- });
127
- await Promise.all(removedAccessTokens);
128
- this.setAccessTokenCredential(credential);
129
- }
130
- /**
131
- * retrieve accounts matching all provided filters; if no filter is set, get all accounts
132
- * not checking for casing as keys are all generated in lower case, remember to convert to lower case if object properties are compared
133
- * @param homeAccountId
134
- * @param environment
135
- * @param realm
136
- */
137
- getAccountsFilteredBy(accountFilter) {
138
- const allAccountKeys = this.getAccountKeys();
139
- const matchingAccounts = [];
140
- allAccountKeys.forEach((cacheKey) => {
141
- if (!this.isAccountKey(cacheKey, accountFilter.homeAccountId, accountFilter.realm)) {
142
- // Don't parse value if the key doesn't match the account filters
143
- return;
144
- }
145
- const entity = this.getAccount(cacheKey);
146
- if (!entity) {
147
- return;
148
- }
149
- if (!!accountFilter.homeAccountId &&
150
- !this.matchHomeAccountId(entity, accountFilter.homeAccountId)) {
151
- return;
152
- }
153
- if (!!accountFilter.localAccountId &&
154
- !this.matchLocalAccountId(entity, accountFilter.localAccountId)) {
155
- return;
156
- }
157
- if (!!accountFilter.username &&
158
- !this.matchUsername(entity, accountFilter.username)) {
159
- return;
160
- }
161
- if (!!accountFilter.environment &&
162
- !this.matchEnvironment(entity, accountFilter.environment)) {
163
- return;
164
- }
165
- if (!!accountFilter.realm &&
166
- !this.matchRealm(entity, accountFilter.realm)) {
167
- return;
168
- }
169
- if (!!accountFilter.nativeAccountId &&
170
- !this.matchNativeAccountId(entity, accountFilter.nativeAccountId)) {
171
- return;
172
- }
173
- matchingAccounts.push(entity);
174
- });
175
- return matchingAccounts;
176
- }
177
- /**
178
- * Returns true if the given key matches our account key schema. Also matches homeAccountId and/or tenantId if provided
179
- * @param key
180
- * @param homeAccountId
181
- * @param tenantId
182
- * @returns
183
- */
184
- isAccountKey(key, homeAccountId, tenantId) {
185
- if (key.split(Separators.CACHE_KEY_SEPARATOR).length < 3) {
186
- // Account cache keys contain 3 items separated by '-' (each item may also contain '-')
187
- return false;
188
- }
189
- if (homeAccountId &&
190
- !key.toLowerCase().includes(homeAccountId.toLowerCase())) {
191
- return false;
192
- }
193
- if (tenantId && !key.toLowerCase().includes(tenantId.toLowerCase())) {
194
- return false;
195
- }
196
- // Do not check environment as aliasing can cause false negatives
197
- return true;
198
- }
199
- /**
200
- * Returns true if the given key matches our credential key schema.
201
- * @param key
202
- */
203
- isCredentialKey(key) {
204
- if (key.split(Separators.CACHE_KEY_SEPARATOR).length < 6) {
205
- // Credential cache keys contain 6 items separated by '-' (each item may also contain '-')
206
- return false;
207
- }
208
- const lowerCaseKey = key.toLowerCase();
209
- // Credential keys must indicate what credential type they represent
210
- if (lowerCaseKey.indexOf(CredentialType.ID_TOKEN.toLowerCase()) ===
211
- -1 &&
212
- lowerCaseKey.indexOf(CredentialType.ACCESS_TOKEN.toLowerCase()) ===
213
- -1 &&
214
- lowerCaseKey.indexOf(CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME.toLowerCase()) === -1 &&
215
- lowerCaseKey.indexOf(CredentialType.REFRESH_TOKEN.toLowerCase()) ===
216
- -1) {
217
- return false;
218
- }
219
- if (lowerCaseKey.indexOf(CredentialType.REFRESH_TOKEN.toLowerCase()) >
220
- -1) {
221
- // Refresh tokens must contain the client id or family id
222
- const clientIdValidation = `${CredentialType.REFRESH_TOKEN}${Separators.CACHE_KEY_SEPARATOR}${this.clientId}${Separators.CACHE_KEY_SEPARATOR}`;
223
- const familyIdValidation = `${CredentialType.REFRESH_TOKEN}${Separators.CACHE_KEY_SEPARATOR}${THE_FAMILY_ID}${Separators.CACHE_KEY_SEPARATOR}`;
224
- if (lowerCaseKey.indexOf(clientIdValidation.toLowerCase()) === -1 &&
225
- lowerCaseKey.indexOf(familyIdValidation.toLowerCase()) === -1) {
226
- return false;
227
- }
228
- }
229
- else if (lowerCaseKey.indexOf(this.clientId.toLowerCase()) === -1) {
230
- // Tokens must contain the clientId
231
- return false;
232
- }
233
- return true;
234
- }
235
- /**
236
- * Returns whether or not the given credential entity matches the filter
237
- * @param entity
238
- * @param filter
239
- * @returns
240
- */
241
- credentialMatchesFilter(entity, filter) {
242
- if (!!filter.clientId && !this.matchClientId(entity, filter.clientId)) {
243
- return false;
244
- }
245
- if (!!filter.userAssertionHash &&
246
- !this.matchUserAssertionHash(entity, filter.userAssertionHash)) {
247
- return false;
248
- }
249
- /*
250
- * homeAccountId can be undefined, and we want to filter out cached items that have a homeAccountId of ""
251
- * because we don't want a client_credential request to return a cached token that has a homeAccountId
252
- */
253
- if (typeof filter.homeAccountId === "string" &&
254
- !this.matchHomeAccountId(entity, filter.homeAccountId)) {
255
- return false;
256
- }
257
- if (!!filter.environment &&
258
- !this.matchEnvironment(entity, filter.environment)) {
259
- return false;
260
- }
261
- if (!!filter.realm && !this.matchRealm(entity, filter.realm)) {
262
- return false;
263
- }
264
- if (!!filter.credentialType &&
265
- !this.matchCredentialType(entity, filter.credentialType)) {
266
- return false;
267
- }
268
- if (!!filter.familyId && !this.matchFamilyId(entity, filter.familyId)) {
269
- return false;
270
- }
271
- /*
272
- * idTokens do not have "target", target specific refreshTokens do exist for some types of authentication
273
- * Resource specific refresh tokens case will be added when the support is deemed necessary
274
- */
275
- if (!!filter.target && !this.matchTarget(entity, filter.target)) {
276
- return false;
277
- }
278
- // If request OR cached entity has requested Claims Hash, check if they match
279
- if (filter.requestedClaimsHash || entity.requestedClaimsHash) {
280
- // Don't match if either is undefined or they are different
281
- if (entity.requestedClaimsHash !== filter.requestedClaimsHash) {
282
- return false;
283
- }
284
- }
285
- // Access Token with Auth Scheme specific matching
286
- if (entity.credentialType ===
287
- CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME) {
288
- if (!!filter.tokenType &&
289
- !this.matchTokenType(entity, filter.tokenType)) {
290
- return false;
291
- }
292
- // KeyId (sshKid) in request must match cached SSH certificate keyId because SSH cert is bound to a specific key
293
- if (filter.tokenType === AuthenticationScheme.SSH) {
294
- if (filter.keyId && !this.matchKeyId(entity, filter.keyId)) {
295
- return false;
296
- }
297
- }
298
- }
299
- return true;
300
- }
301
- /**
302
- * retrieve appMetadata matching all provided filters; if no filter is set, get all appMetadata
303
- * @param filter
304
- */
305
- getAppMetadataFilteredBy(filter) {
306
- return this.getAppMetadataFilteredByInternal(filter.environment, filter.clientId);
307
- }
308
- /**
309
- * Support function to help match appMetadata
310
- * @param environment
311
- * @param clientId
312
- */
313
- getAppMetadataFilteredByInternal(environment, clientId) {
314
- const allCacheKeys = this.getKeys();
315
- const matchingAppMetadata = {};
316
- allCacheKeys.forEach((cacheKey) => {
317
- // don't parse any non-appMetadata type cache entities
318
- if (!this.isAppMetadata(cacheKey)) {
319
- return;
320
- }
321
- // Attempt retrieval
322
- const entity = this.getAppMetadata(cacheKey);
323
- if (!entity) {
324
- return;
325
- }
326
- if (!!environment && !this.matchEnvironment(entity, environment)) {
327
- return;
328
- }
329
- if (!!clientId && !this.matchClientId(entity, clientId)) {
330
- return;
331
- }
332
- matchingAppMetadata[cacheKey] = entity;
333
- });
334
- return matchingAppMetadata;
335
- }
336
- /**
337
- * retrieve authorityMetadata that contains a matching alias
338
- * @param filter
339
- */
340
- getAuthorityMetadataByAlias(host) {
341
- const allCacheKeys = this.getAuthorityMetadataKeys();
342
- let matchedEntity = null;
343
- allCacheKeys.forEach((cacheKey) => {
344
- // don't parse any non-authorityMetadata type cache entities
345
- if (!this.isAuthorityMetadata(cacheKey) ||
346
- cacheKey.indexOf(this.clientId) === -1) {
347
- return;
348
- }
349
- // Attempt retrieval
350
- const entity = this.getAuthorityMetadata(cacheKey);
351
- if (!entity) {
352
- return;
353
- }
354
- if (entity.aliases.indexOf(host) === -1) {
355
- return;
356
- }
357
- matchedEntity = entity;
358
- });
359
- return matchedEntity;
360
- }
361
- /**
362
- * Removes all accounts and related tokens from cache.
363
- */
364
- async removeAllAccounts() {
365
- const allAccountKeys = this.getAccountKeys();
366
- const removedAccounts = [];
367
- allAccountKeys.forEach((cacheKey) => {
368
- removedAccounts.push(this.removeAccount(cacheKey));
369
- });
370
- await Promise.all(removedAccounts);
371
- }
372
- /**
373
- * Removes the account and related tokens for a given account key
374
- * @param account
375
- */
376
- async removeAccount(accountKey) {
377
- const account = this.getAccount(accountKey);
378
- if (!account) {
379
- return;
380
- }
381
- await this.removeAccountContext(account);
382
- this.removeItem(accountKey);
383
- }
384
- /**
385
- * Removes credentials associated with the provided account
386
- * @param account
387
- */
388
- async removeAccountContext(account) {
389
- const allTokenKeys = this.getTokenKeys();
390
- const accountId = account.generateAccountId();
391
- const removedCredentials = [];
392
- allTokenKeys.idToken.forEach((key) => {
393
- if (key.indexOf(accountId) === 0) {
394
- this.removeIdToken(key);
395
- }
396
- });
397
- allTokenKeys.accessToken.forEach((key) => {
398
- if (key.indexOf(accountId) === 0) {
399
- removedCredentials.push(this.removeAccessToken(key));
400
- }
401
- });
402
- allTokenKeys.refreshToken.forEach((key) => {
403
- if (key.indexOf(accountId) === 0) {
404
- this.removeRefreshToken(key);
405
- }
406
- });
407
- await Promise.all(removedCredentials);
408
- }
409
- /**
410
- * returns a boolean if the given credential is removed
411
- * @param credential
412
- */
413
- async removeAccessToken(key) {
414
- const credential = this.getAccessTokenCredential(key);
415
- if (!credential) {
416
- return;
417
- }
418
- // Remove Token Binding Key from key store for PoP Tokens Credentials
419
- if (credential.credentialType.toLowerCase() ===
420
- CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME.toLowerCase()) {
421
- if (credential.tokenType === AuthenticationScheme.POP) {
422
- const accessTokenWithAuthSchemeEntity = credential;
423
- const kid = accessTokenWithAuthSchemeEntity.keyId;
424
- if (kid) {
425
- try {
426
- await this.cryptoImpl.removeTokenBindingKey(kid);
427
- }
428
- catch (error) {
429
- throw createClientAuthError(bindingKeyNotRemoved);
430
- }
431
- }
432
- }
433
- }
434
- return this.removeItem(key);
435
- }
436
- /**
437
- * Removes all app metadata objects from cache.
438
- */
439
- removeAppMetadata() {
440
- const allCacheKeys = this.getKeys();
441
- allCacheKeys.forEach((cacheKey) => {
442
- if (this.isAppMetadata(cacheKey)) {
443
- this.removeItem(cacheKey);
444
- }
445
- });
446
- return true;
447
- }
448
- /**
449
- * Retrieve the cached credentials into a cacherecord
450
- * @param account
451
- * @param clientId
452
- * @param scopes
453
- * @param environment
454
- * @param authScheme
455
- */
456
- readCacheRecord(account, request, environment) {
457
- const tokenKeys = this.getTokenKeys();
458
- const cachedAccount = this.readAccountFromCache(account);
459
- const cachedIdToken = this.getIdToken(account, tokenKeys);
460
- const cachedAccessToken = this.getAccessToken(account, request, tokenKeys);
461
- const cachedRefreshToken = this.getRefreshToken(account, false, tokenKeys);
462
- const cachedAppMetadata = this.readAppMetadataFromCache(environment);
463
- if (cachedAccount && cachedIdToken) {
464
- cachedAccount.idTokenClaims = extractTokenClaims(cachedIdToken.secret, this.cryptoImpl.base64Decode);
465
- }
466
- return {
467
- account: cachedAccount,
468
- idToken: cachedIdToken,
469
- accessToken: cachedAccessToken,
470
- refreshToken: cachedRefreshToken,
471
- appMetadata: cachedAppMetadata,
472
- };
473
- }
474
- /**
475
- * Retrieve AccountEntity from cache
476
- * @param account
477
- */
478
- readAccountFromCache(account) {
479
- const accountKey = AccountEntity.generateAccountCacheKey(account);
480
- return this.getAccount(accountKey);
481
- }
482
- /**
483
- * Retrieve IdTokenEntity from cache
484
- * @param clientId
485
- * @param account
486
- * @param inputRealm
487
- */
488
- getIdToken(account, tokenKeys) {
489
- this.commonLogger.trace("CacheManager - getIdToken called");
490
- const idTokenFilter = {
491
- homeAccountId: account.homeAccountId,
492
- environment: account.environment,
493
- credentialType: CredentialType.ID_TOKEN,
494
- clientId: this.clientId,
495
- realm: account.tenantId,
496
- };
497
- const idTokens = this.getIdTokensByFilter(idTokenFilter, tokenKeys);
498
- const numIdTokens = idTokens.length;
499
- if (numIdTokens < 1) {
500
- this.commonLogger.info("CacheManager:getIdToken - No token found");
501
- return null;
502
- }
503
- else if (numIdTokens > 1) {
504
- this.commonLogger.info("CacheManager:getIdToken - Multiple id tokens found, clearing them");
505
- idTokens.forEach((idToken) => {
506
- this.removeIdToken(idToken.generateCredentialKey());
507
- });
508
- return null;
509
- }
510
- this.commonLogger.info("CacheManager:getIdToken - Returning id token");
511
- return idTokens[0];
512
- }
513
- /**
514
- * Gets all idTokens matching the given filter
515
- * @param filter
516
- * @returns
517
- */
518
- getIdTokensByFilter(filter, tokenKeys) {
519
- const idTokenKeys = (tokenKeys && tokenKeys.idToken) || this.getTokenKeys().idToken;
520
- const idTokens = [];
521
- idTokenKeys.forEach((key) => {
522
- if (!this.idTokenKeyMatchesFilter(key, {
523
- clientId: this.clientId,
524
- ...filter,
525
- })) {
526
- return;
527
- }
528
- const idToken = this.getIdTokenCredential(key);
529
- if (idToken && this.credentialMatchesFilter(idToken, filter)) {
530
- idTokens.push(idToken);
531
- }
532
- });
533
- return idTokens;
534
- }
535
- /**
536
- * Validate the cache key against filter before retrieving and parsing cache value
537
- * @param key
538
- * @param filter
539
- * @returns
540
- */
541
- idTokenKeyMatchesFilter(inputKey, filter) {
542
- const key = inputKey.toLowerCase();
543
- if (filter.clientId &&
544
- key.indexOf(filter.clientId.toLowerCase()) === -1) {
545
- return false;
546
- }
547
- if (filter.homeAccountId &&
548
- key.indexOf(filter.homeAccountId.toLowerCase()) === -1) {
549
- return false;
550
- }
551
- return true;
552
- }
553
- /**
554
- * Removes idToken from the cache
555
- * @param key
556
- */
557
- removeIdToken(key) {
558
- this.removeItem(key);
559
- }
560
- /**
561
- * Removes refresh token from the cache
562
- * @param key
563
- */
564
- removeRefreshToken(key) {
565
- this.removeItem(key);
566
- }
567
- /**
568
- * Retrieve AccessTokenEntity from cache
569
- * @param clientId
570
- * @param account
571
- * @param scopes
572
- * @param authScheme
573
- */
574
- getAccessToken(account, request, tokenKeys) {
575
- this.commonLogger.trace("CacheManager - getAccessToken called");
576
- const scopes = ScopeSet.createSearchScopes(request.scopes);
577
- const authScheme = request.authenticationScheme || AuthenticationScheme.BEARER;
578
- /*
579
- * Distinguish between Bearer and PoP/SSH token cache types
580
- * Cast to lowercase to handle "bearer" from ADFS
581
- */
582
- const credentialType = authScheme &&
583
- authScheme.toLowerCase() !==
584
- AuthenticationScheme.BEARER.toLowerCase()
585
- ? CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME
586
- : CredentialType.ACCESS_TOKEN;
587
- const accessTokenFilter = {
588
- homeAccountId: account.homeAccountId,
589
- environment: account.environment,
590
- credentialType: credentialType,
591
- clientId: this.clientId,
592
- realm: account.tenantId,
593
- target: scopes,
594
- tokenType: authScheme,
595
- keyId: request.sshKid,
596
- requestedClaimsHash: request.requestedClaimsHash,
597
- };
598
- const accessTokenKeys = (tokenKeys && tokenKeys.accessToken) ||
599
- this.getTokenKeys().accessToken;
600
- const accessTokens = [];
601
- accessTokenKeys.forEach((key) => {
602
- // Validate key
603
- if (this.accessTokenKeyMatchesFilter(key, accessTokenFilter, true)) {
604
- const accessToken = this.getAccessTokenCredential(key);
605
- // Validate value
606
- if (accessToken &&
607
- this.credentialMatchesFilter(accessToken, accessTokenFilter)) {
608
- accessTokens.push(accessToken);
609
- }
610
- }
611
- });
612
- const numAccessTokens = accessTokens.length;
613
- if (numAccessTokens < 1) {
614
- this.commonLogger.info("CacheManager:getAccessToken - No token found");
615
- return null;
616
- }
617
- else if (numAccessTokens > 1) {
618
- this.commonLogger.info("CacheManager:getAccessToken - Multiple access tokens found, clearing them");
619
- accessTokens.forEach((accessToken) => {
620
- void this.removeAccessToken(accessToken.generateCredentialKey());
621
- });
622
- return null;
623
- }
624
- this.commonLogger.info("CacheManager:getAccessToken - Returning access token");
625
- return accessTokens[0];
626
- }
627
- /**
628
- * Validate the cache key against filter before retrieving and parsing cache value
629
- * @param key
630
- * @param filter
631
- * @param keyMustContainAllScopes
632
- * @returns
633
- */
634
- accessTokenKeyMatchesFilter(inputKey, filter, keyMustContainAllScopes) {
635
- const key = inputKey.toLowerCase();
636
- if (filter.clientId &&
637
- key.indexOf(filter.clientId.toLowerCase()) === -1) {
638
- return false;
639
- }
640
- if (filter.homeAccountId &&
641
- key.indexOf(filter.homeAccountId.toLowerCase()) === -1) {
642
- return false;
643
- }
644
- if (filter.realm && key.indexOf(filter.realm.toLowerCase()) === -1) {
645
- return false;
646
- }
647
- if (filter.requestedClaimsHash &&
648
- key.indexOf(filter.requestedClaimsHash.toLowerCase()) === -1) {
649
- return false;
650
- }
651
- if (filter.target) {
652
- const scopes = filter.target.asArray();
653
- for (let i = 0; i < scopes.length; i++) {
654
- if (keyMustContainAllScopes &&
655
- !key.includes(scopes[i].toLowerCase())) {
656
- // When performing a cache lookup a missing scope would be a cache miss
657
- return false;
658
- }
659
- else if (!keyMustContainAllScopes &&
660
- key.includes(scopes[i].toLowerCase())) {
661
- // When performing a cache write, any token with a subset of requested scopes should be replaced
662
- return true;
663
- }
664
- }
665
- }
666
- return true;
667
- }
668
- /**
669
- * Gets all access tokens matching the filter
670
- * @param filter
671
- * @returns
672
- */
673
- getAccessTokensByFilter(filter) {
674
- const tokenKeys = this.getTokenKeys();
675
- const accessTokens = [];
676
- tokenKeys.accessToken.forEach((key) => {
677
- if (!this.accessTokenKeyMatchesFilter(key, filter, true)) {
678
- return;
679
- }
680
- const accessToken = this.getAccessTokenCredential(key);
681
- if (accessToken &&
682
- this.credentialMatchesFilter(accessToken, filter)) {
683
- accessTokens.push(accessToken);
684
- }
685
- });
686
- return accessTokens;
687
- }
688
- /**
689
- * Helper to retrieve the appropriate refresh token from cache
690
- * @param clientId
691
- * @param account
692
- * @param familyRT
693
- */
694
- getRefreshToken(account, familyRT, tokenKeys) {
695
- this.commonLogger.trace("CacheManager - getRefreshToken called");
696
- const id = familyRT ? THE_FAMILY_ID : undefined;
697
- const refreshTokenFilter = {
698
- homeAccountId: account.homeAccountId,
699
- environment: account.environment,
700
- credentialType: CredentialType.REFRESH_TOKEN,
701
- clientId: this.clientId,
702
- familyId: id,
703
- };
704
- const refreshTokenKeys = (tokenKeys && tokenKeys.refreshToken) ||
705
- this.getTokenKeys().refreshToken;
706
- const refreshTokens = [];
707
- refreshTokenKeys.forEach((key) => {
708
- // Validate key
709
- if (this.refreshTokenKeyMatchesFilter(key, refreshTokenFilter)) {
710
- const refreshToken = this.getRefreshTokenCredential(key);
711
- // Validate value
712
- if (refreshToken &&
713
- this.credentialMatchesFilter(refreshToken, refreshTokenFilter)) {
714
- refreshTokens.push(refreshToken);
715
- }
716
- }
717
- });
718
- const numRefreshTokens = refreshTokens.length;
719
- if (numRefreshTokens < 1) {
720
- this.commonLogger.info("CacheManager:getRefreshToken - No refresh token found.");
721
- return null;
722
- }
723
- // address the else case after remove functions address environment aliases
724
- this.commonLogger.info("CacheManager:getRefreshToken - returning refresh token");
725
- return refreshTokens[0];
726
- }
727
- /**
728
- * Validate the cache key against filter before retrieving and parsing cache value
729
- * @param key
730
- * @param filter
731
- */
732
- refreshTokenKeyMatchesFilter(inputKey, filter) {
733
- const key = inputKey.toLowerCase();
734
- if (filter.familyId &&
735
- key.indexOf(filter.familyId.toLowerCase()) === -1) {
736
- return false;
737
- }
738
- // If familyId is used, clientId is not in the key
739
- if (!filter.familyId &&
740
- filter.clientId &&
741
- key.indexOf(filter.clientId.toLowerCase()) === -1) {
742
- return false;
743
- }
744
- if (filter.homeAccountId &&
745
- key.indexOf(filter.homeAccountId.toLowerCase()) === -1) {
746
- return false;
747
- }
748
- return true;
749
- }
750
- /**
751
- * Retrieve AppMetadataEntity from cache
752
- */
753
- readAppMetadataFromCache(environment) {
754
- const appMetadataFilter = {
755
- environment,
756
- clientId: this.clientId,
757
- };
758
- const appMetadata = this.getAppMetadataFilteredBy(appMetadataFilter);
759
- const appMetadataEntries = Object.keys(appMetadata).map((key) => appMetadata[key]);
760
- const numAppMetadata = appMetadataEntries.length;
761
- if (numAppMetadata < 1) {
762
- return null;
763
- }
764
- else if (numAppMetadata > 1) {
765
- throw createClientAuthError(multipleMatchingAppMetadata);
766
- }
767
- return appMetadataEntries[0];
768
- }
769
- /**
770
- * Return the family_id value associated with FOCI
771
- * @param environment
772
- * @param clientId
773
- */
774
- isAppMetadataFOCI(environment) {
775
- const appMetadata = this.readAppMetadataFromCache(environment);
776
- return !!(appMetadata && appMetadata.familyId === THE_FAMILY_ID);
777
- }
778
- /**
779
- * helper to match account ids
780
- * @param value
781
- * @param homeAccountId
782
- */
783
- matchHomeAccountId(entity, homeAccountId) {
784
- return !!(typeof entity.homeAccountId === "string" &&
785
- homeAccountId === entity.homeAccountId);
786
- }
787
- /**
788
- * helper to match account ids
789
- * @param entity
790
- * @param localAccountId
791
- * @returns
792
- */
793
- matchLocalAccountId(entity, localAccountId) {
794
- return !!(typeof entity.localAccountId === "string" &&
795
- localAccountId === entity.localAccountId);
796
- }
797
- /**
798
- * helper to match usernames
799
- * @param entity
800
- * @param username
801
- * @returns
802
- */
803
- matchUsername(entity, username) {
804
- return !!(typeof entity.username === "string" &&
805
- username.toLowerCase() === entity.username.toLowerCase());
806
- }
807
- /**
808
- * helper to match assertion
809
- * @param value
810
- * @param oboAssertion
811
- */
812
- matchUserAssertionHash(entity, userAssertionHash) {
813
- return !!(entity.userAssertionHash &&
814
- userAssertionHash === entity.userAssertionHash);
815
- }
816
- /**
817
- * helper to match environment
818
- * @param value
819
- * @param environment
820
- */
821
- matchEnvironment(entity, environment) {
822
- const cloudMetadata = this.getAuthorityMetadataByAlias(environment);
823
- if (cloudMetadata &&
824
- cloudMetadata.aliases.indexOf(entity.environment) > -1) {
825
- return true;
826
- }
827
- return false;
828
- }
829
- /**
830
- * helper to match credential type
831
- * @param entity
832
- * @param credentialType
833
- */
834
- matchCredentialType(entity, credentialType) {
835
- return (entity.credentialType &&
836
- credentialType.toLowerCase() === entity.credentialType.toLowerCase());
837
- }
838
- /**
839
- * helper to match client ids
840
- * @param entity
841
- * @param clientId
842
- */
843
- matchClientId(entity, clientId) {
844
- return !!(entity.clientId && clientId === entity.clientId);
845
- }
846
- /**
847
- * helper to match family ids
848
- * @param entity
849
- * @param familyId
850
- */
851
- matchFamilyId(entity, familyId) {
852
- return !!(entity.familyId && familyId === entity.familyId);
853
- }
854
- /**
855
- * helper to match realm
856
- * @param entity
857
- * @param realm
858
- */
859
- matchRealm(entity, realm) {
860
- return !!(entity.realm && realm === entity.realm);
861
- }
862
- /**
863
- * helper to match nativeAccountId
864
- * @param entity
865
- * @param nativeAccountId
866
- * @returns boolean indicating the match result
867
- */
868
- matchNativeAccountId(entity, nativeAccountId) {
869
- return !!(entity.nativeAccountId && nativeAccountId === entity.nativeAccountId);
870
- }
871
- /**
872
- * Returns true if the target scopes are a subset of the current entity's scopes, false otherwise.
873
- * @param entity
874
- * @param target
875
- */
876
- matchTarget(entity, target) {
877
- const isNotAccessTokenCredential = entity.credentialType !== CredentialType.ACCESS_TOKEN &&
878
- entity.credentialType !==
879
- CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME;
880
- if (isNotAccessTokenCredential || !entity.target) {
881
- return false;
882
- }
883
- const entityScopeSet = ScopeSet.fromString(entity.target);
884
- return entityScopeSet.containsScopeSet(target);
885
- }
886
- /**
887
- * Returns true if the credential's tokenType or Authentication Scheme matches the one in the request, false otherwise
888
- * @param entity
889
- * @param tokenType
890
- */
891
- matchTokenType(entity, tokenType) {
892
- return !!(entity.tokenType && entity.tokenType === tokenType);
893
- }
894
- /**
895
- * Returns true if the credential's keyId matches the one in the request, false otherwise
896
- * @param entity
897
- * @param tokenType
898
- */
899
- matchKeyId(entity, keyId) {
900
- return !!(entity.keyId && entity.keyId === keyId);
901
- }
902
- /**
903
- * returns if a given cache entity is of the type appmetadata
904
- * @param key
905
- */
906
- isAppMetadata(key) {
907
- return key.indexOf(APP_METADATA) !== -1;
908
- }
909
- /**
910
- * returns if a given cache entity is of the type authoritymetadata
911
- * @param key
912
- */
913
- isAuthorityMetadata(key) {
914
- return key.indexOf(AUTHORITY_METADATA_CONSTANTS.CACHE_KEY) !== -1;
915
- }
916
- /**
917
- * returns cache key used for cloud instance metadata
918
- */
919
- generateAuthorityMetadataCacheKey(authority) {
920
- return `${AUTHORITY_METADATA_CONSTANTS.CACHE_KEY}-${this.clientId}-${authority}`;
921
- }
922
- /**
923
- * Helper to convert serialized data to object
924
- * @param obj
925
- * @param json
926
- */
927
- static toObject(obj, json) {
928
- for (const propertyName in json) {
929
- obj[propertyName] = json[propertyName];
930
- }
931
- return obj;
932
- }
933
- }
934
- /** @internal */
935
- class DefaultStorageClass extends CacheManager {
936
- setAccount() {
937
- throw createClientAuthError(methodNotImplemented);
938
- }
939
- getAccount() {
940
- throw createClientAuthError(methodNotImplemented);
941
- }
942
- setIdTokenCredential() {
943
- throw createClientAuthError(methodNotImplemented);
944
- }
945
- getIdTokenCredential() {
946
- throw createClientAuthError(methodNotImplemented);
947
- }
948
- setAccessTokenCredential() {
949
- throw createClientAuthError(methodNotImplemented);
950
- }
951
- getAccessTokenCredential() {
952
- throw createClientAuthError(methodNotImplemented);
953
- }
954
- setRefreshTokenCredential() {
955
- throw createClientAuthError(methodNotImplemented);
956
- }
957
- getRefreshTokenCredential() {
958
- throw createClientAuthError(methodNotImplemented);
959
- }
960
- setAppMetadata() {
961
- throw createClientAuthError(methodNotImplemented);
962
- }
963
- getAppMetadata() {
964
- throw createClientAuthError(methodNotImplemented);
965
- }
966
- setServerTelemetry() {
967
- throw createClientAuthError(methodNotImplemented);
968
- }
969
- getServerTelemetry() {
970
- throw createClientAuthError(methodNotImplemented);
971
- }
972
- setAuthorityMetadata() {
973
- throw createClientAuthError(methodNotImplemented);
974
- }
975
- getAuthorityMetadata() {
976
- throw createClientAuthError(methodNotImplemented);
977
- }
978
- getAuthorityMetadataKeys() {
979
- throw createClientAuthError(methodNotImplemented);
980
- }
981
- setThrottlingCache() {
982
- throw createClientAuthError(methodNotImplemented);
983
- }
984
- getThrottlingCache() {
985
- throw createClientAuthError(methodNotImplemented);
986
- }
987
- removeItem() {
988
- throw createClientAuthError(methodNotImplemented);
989
- }
990
- containsKey() {
991
- throw createClientAuthError(methodNotImplemented);
992
- }
993
- getKeys() {
994
- throw createClientAuthError(methodNotImplemented);
995
- }
996
- getAccountKeys() {
997
- throw createClientAuthError(methodNotImplemented);
998
- }
999
- getTokenKeys() {
1000
- throw createClientAuthError(methodNotImplemented);
1001
- }
1002
- async clear() {
1003
- throw createClientAuthError(methodNotImplemented);
1004
- }
1005
- updateCredentialCacheKey() {
1006
- throw createClientAuthError(methodNotImplemented);
1007
- }
11
+ /*
12
+ * Copyright (c) Microsoft Corporation. All rights reserved.
13
+ * Licensed under the MIT License.
14
+ */
15
+ /**
16
+ * Interface class which implement cache storage functions used by MSAL to perform validity checks, and store tokens.
17
+ * @internal
18
+ */
19
+ class CacheManager {
20
+ constructor(clientId, cryptoImpl, logger) {
21
+ this.clientId = clientId;
22
+ this.cryptoImpl = cryptoImpl;
23
+ this.commonLogger = logger.clone(name, version);
24
+ }
25
+ /**
26
+ * Returns all the accounts in the cache that match the optional filter. If no filter is provided, all accounts are returned.
27
+ * @param accountFilter - (Optional) filter to narrow down the accounts returned
28
+ * @returns Array of AccountInfo objects in cache
29
+ */
30
+ getAllAccounts(accountFilter) {
31
+ if (accountFilter) {
32
+ return this.getAccountsFilteredBy(accountFilter).map((accountEntity) => {
33
+ return accountEntity.getAccountInfo();
34
+ });
35
+ }
36
+ const allAccountKeys = this.getAccountKeys();
37
+ if (allAccountKeys.length < 1) {
38
+ return [];
39
+ }
40
+ const accountEntities = allAccountKeys.reduce((accounts, key) => {
41
+ const entity = this.getAccount(key);
42
+ if (!entity) {
43
+ return accounts;
44
+ }
45
+ accounts.push(entity);
46
+ return accounts;
47
+ }, []);
48
+ const allAccounts = accountEntities.map((accountEntity) => {
49
+ return this.getAccountInfoFromEntity(accountEntity);
50
+ });
51
+ return allAccounts;
52
+ }
53
+ /**
54
+ * Gets accountInfo object based on provided filters
55
+ */
56
+ getAccountInfoFilteredBy(accountFilter) {
57
+ const allAccounts = this.getAccountsFilteredBy(accountFilter);
58
+ if (allAccounts.length > 0) {
59
+ return this.getAccountInfoFromEntity(allAccounts[0]);
60
+ }
61
+ else {
62
+ return null;
63
+ }
64
+ }
65
+ getAccountInfoFromEntity(accountEntity) {
66
+ const accountInfo = accountEntity.getAccountInfo();
67
+ const idToken = this.getIdToken(accountInfo);
68
+ if (idToken) {
69
+ accountInfo.idToken = idToken.secret;
70
+ accountInfo.idTokenClaims = extractTokenClaims(idToken.secret, this.cryptoImpl.base64Decode);
71
+ }
72
+ return accountInfo;
73
+ }
74
+ /**
75
+ * saves a cache record
76
+ * @param cacheRecord
77
+ */
78
+ async saveCacheRecord(cacheRecord, storeInCache) {
79
+ if (!cacheRecord) {
80
+ throw createClientAuthError(invalidCacheRecord);
81
+ }
82
+ if (!!cacheRecord.account) {
83
+ this.setAccount(cacheRecord.account);
84
+ }
85
+ if (!!cacheRecord.idToken && storeInCache?.idToken !== false) {
86
+ this.setIdTokenCredential(cacheRecord.idToken);
87
+ }
88
+ if (!!cacheRecord.accessToken && storeInCache?.accessToken !== false) {
89
+ await this.saveAccessToken(cacheRecord.accessToken);
90
+ }
91
+ if (!!cacheRecord.refreshToken &&
92
+ storeInCache?.refreshToken !== false) {
93
+ this.setRefreshTokenCredential(cacheRecord.refreshToken);
94
+ }
95
+ if (!!cacheRecord.appMetadata) {
96
+ this.setAppMetadata(cacheRecord.appMetadata);
97
+ }
98
+ }
99
+ /**
100
+ * saves access token credential
101
+ * @param credential
102
+ */
103
+ async saveAccessToken(credential) {
104
+ const accessTokenFilter = {
105
+ clientId: credential.clientId,
106
+ credentialType: credential.credentialType,
107
+ environment: credential.environment,
108
+ homeAccountId: credential.homeAccountId,
109
+ realm: credential.realm,
110
+ tokenType: credential.tokenType,
111
+ requestedClaimsHash: credential.requestedClaimsHash,
112
+ };
113
+ const tokenKeys = this.getTokenKeys();
114
+ const currentScopes = ScopeSet.fromString(credential.target);
115
+ const removedAccessTokens = [];
116
+ tokenKeys.accessToken.forEach((key) => {
117
+ if (!this.accessTokenKeyMatchesFilter(key, accessTokenFilter, false)) {
118
+ return;
119
+ }
120
+ const tokenEntity = this.getAccessTokenCredential(key);
121
+ if (tokenEntity &&
122
+ this.credentialMatchesFilter(tokenEntity, accessTokenFilter)) {
123
+ const tokenScopeSet = ScopeSet.fromString(tokenEntity.target);
124
+ if (tokenScopeSet.intersectingScopeSets(currentScopes)) {
125
+ removedAccessTokens.push(this.removeAccessToken(key));
126
+ }
127
+ }
128
+ });
129
+ await Promise.all(removedAccessTokens);
130
+ this.setAccessTokenCredential(credential);
131
+ }
132
+ /**
133
+ * Retrieve accounts matching all provided filters; if no filter is set, get all accounts
134
+ * Not checking for casing as keys are all generated in lower case, remember to convert to lower case if object properties are compared
135
+ * @param accountFilter - An object containing Account properties to filter by
136
+ */
137
+ getAccountsFilteredBy(accountFilter) {
138
+ const allAccountKeys = this.getAccountKeys();
139
+ const matchingAccounts = [];
140
+ allAccountKeys.forEach((cacheKey) => {
141
+ if (!this.isAccountKey(cacheKey, accountFilter.homeAccountId, accountFilter.tenantId)) {
142
+ // Don't parse value if the key doesn't match the account filters
143
+ return;
144
+ }
145
+ const entity = this.getAccount(cacheKey);
146
+ if (!entity) {
147
+ return;
148
+ }
149
+ if (!!accountFilter.homeAccountId &&
150
+ !this.matchHomeAccountId(entity, accountFilter.homeAccountId)) {
151
+ return;
152
+ }
153
+ if (!!accountFilter.localAccountId &&
154
+ !this.matchLocalAccountId(entity, accountFilter.localAccountId)) {
155
+ return;
156
+ }
157
+ if (!!accountFilter.username &&
158
+ !this.matchUsername(entity, accountFilter.username)) {
159
+ return;
160
+ }
161
+ if (!!accountFilter.environment &&
162
+ !this.matchEnvironment(entity, accountFilter.environment)) {
163
+ return;
164
+ }
165
+ if (!!accountFilter.realm &&
166
+ !this.matchRealm(entity, accountFilter.realm)) {
167
+ return;
168
+ }
169
+ // tenantId is another name for realm
170
+ if (!!accountFilter.tenantId &&
171
+ !this.matchRealm(entity, accountFilter.tenantId)) {
172
+ return;
173
+ }
174
+ if (!!accountFilter.nativeAccountId &&
175
+ !this.matchNativeAccountId(entity, accountFilter.nativeAccountId)) {
176
+ return;
177
+ }
178
+ if (!!accountFilter.loginHint &&
179
+ !this.matchLoginHint(entity, accountFilter.loginHint)) {
180
+ return;
181
+ }
182
+ if (!!accountFilter.authorityType &&
183
+ !this.matchAuthorityType(entity, accountFilter.authorityType)) {
184
+ return;
185
+ }
186
+ if (!!accountFilter.name &&
187
+ !this.matchName(entity, accountFilter.name)) {
188
+ return;
189
+ }
190
+ matchingAccounts.push(entity);
191
+ });
192
+ return matchingAccounts;
193
+ }
194
+ /**
195
+ * Returns true if the given key matches our account key schema. Also matches homeAccountId and/or tenantId if provided
196
+ * @param key
197
+ * @param homeAccountId
198
+ * @param tenantId
199
+ * @returns
200
+ */
201
+ isAccountKey(key, homeAccountId, tenantId) {
202
+ if (key.split(Separators.CACHE_KEY_SEPARATOR).length < 3) {
203
+ // Account cache keys contain 3 items separated by '-' (each item may also contain '-')
204
+ return false;
205
+ }
206
+ if (homeAccountId &&
207
+ !key.toLowerCase().includes(homeAccountId.toLowerCase())) {
208
+ return false;
209
+ }
210
+ if (tenantId && !key.toLowerCase().includes(tenantId.toLowerCase())) {
211
+ return false;
212
+ }
213
+ // Do not check environment as aliasing can cause false negatives
214
+ return true;
215
+ }
216
+ /**
217
+ * Returns true if the given key matches our credential key schema.
218
+ * @param key
219
+ */
220
+ isCredentialKey(key) {
221
+ if (key.split(Separators.CACHE_KEY_SEPARATOR).length < 6) {
222
+ // Credential cache keys contain 6 items separated by '-' (each item may also contain '-')
223
+ return false;
224
+ }
225
+ const lowerCaseKey = key.toLowerCase();
226
+ // Credential keys must indicate what credential type they represent
227
+ if (lowerCaseKey.indexOf(CredentialType.ID_TOKEN.toLowerCase()) ===
228
+ -1 &&
229
+ lowerCaseKey.indexOf(CredentialType.ACCESS_TOKEN.toLowerCase()) ===
230
+ -1 &&
231
+ lowerCaseKey.indexOf(CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME.toLowerCase()) === -1 &&
232
+ lowerCaseKey.indexOf(CredentialType.REFRESH_TOKEN.toLowerCase()) ===
233
+ -1) {
234
+ return false;
235
+ }
236
+ if (lowerCaseKey.indexOf(CredentialType.REFRESH_TOKEN.toLowerCase()) >
237
+ -1) {
238
+ // Refresh tokens must contain the client id or family id
239
+ const clientIdValidation = `${CredentialType.REFRESH_TOKEN}${Separators.CACHE_KEY_SEPARATOR}${this.clientId}${Separators.CACHE_KEY_SEPARATOR}`;
240
+ const familyIdValidation = `${CredentialType.REFRESH_TOKEN}${Separators.CACHE_KEY_SEPARATOR}${THE_FAMILY_ID}${Separators.CACHE_KEY_SEPARATOR}`;
241
+ if (lowerCaseKey.indexOf(clientIdValidation.toLowerCase()) === -1 &&
242
+ lowerCaseKey.indexOf(familyIdValidation.toLowerCase()) === -1) {
243
+ return false;
244
+ }
245
+ }
246
+ else if (lowerCaseKey.indexOf(this.clientId.toLowerCase()) === -1) {
247
+ // Tokens must contain the clientId
248
+ return false;
249
+ }
250
+ return true;
251
+ }
252
+ /**
253
+ * Returns whether or not the given credential entity matches the filter
254
+ * @param entity
255
+ * @param filter
256
+ * @returns
257
+ */
258
+ credentialMatchesFilter(entity, filter) {
259
+ if (!!filter.clientId && !this.matchClientId(entity, filter.clientId)) {
260
+ return false;
261
+ }
262
+ if (!!filter.userAssertionHash &&
263
+ !this.matchUserAssertionHash(entity, filter.userAssertionHash)) {
264
+ return false;
265
+ }
266
+ /*
267
+ * homeAccountId can be undefined, and we want to filter out cached items that have a homeAccountId of ""
268
+ * because we don't want a client_credential request to return a cached token that has a homeAccountId
269
+ */
270
+ if (typeof filter.homeAccountId === "string" &&
271
+ !this.matchHomeAccountId(entity, filter.homeAccountId)) {
272
+ return false;
273
+ }
274
+ if (!!filter.environment &&
275
+ !this.matchEnvironment(entity, filter.environment)) {
276
+ return false;
277
+ }
278
+ if (!!filter.realm && !this.matchRealm(entity, filter.realm)) {
279
+ return false;
280
+ }
281
+ if (!!filter.credentialType &&
282
+ !this.matchCredentialType(entity, filter.credentialType)) {
283
+ return false;
284
+ }
285
+ if (!!filter.familyId && !this.matchFamilyId(entity, filter.familyId)) {
286
+ return false;
287
+ }
288
+ /*
289
+ * idTokens do not have "target", target specific refreshTokens do exist for some types of authentication
290
+ * Resource specific refresh tokens case will be added when the support is deemed necessary
291
+ */
292
+ if (!!filter.target && !this.matchTarget(entity, filter.target)) {
293
+ return false;
294
+ }
295
+ // If request OR cached entity has requested Claims Hash, check if they match
296
+ if (filter.requestedClaimsHash || entity.requestedClaimsHash) {
297
+ // Don't match if either is undefined or they are different
298
+ if (entity.requestedClaimsHash !== filter.requestedClaimsHash) {
299
+ return false;
300
+ }
301
+ }
302
+ // Access Token with Auth Scheme specific matching
303
+ if (entity.credentialType ===
304
+ CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME) {
305
+ if (!!filter.tokenType &&
306
+ !this.matchTokenType(entity, filter.tokenType)) {
307
+ return false;
308
+ }
309
+ // KeyId (sshKid) in request must match cached SSH certificate keyId because SSH cert is bound to a specific key
310
+ if (filter.tokenType === AuthenticationScheme.SSH) {
311
+ if (filter.keyId && !this.matchKeyId(entity, filter.keyId)) {
312
+ return false;
313
+ }
314
+ }
315
+ }
316
+ return true;
317
+ }
318
+ /**
319
+ * retrieve appMetadata matching all provided filters; if no filter is set, get all appMetadata
320
+ * @param filter
321
+ */
322
+ getAppMetadataFilteredBy(filter) {
323
+ return this.getAppMetadataFilteredByInternal(filter.environment, filter.clientId);
324
+ }
325
+ /**
326
+ * Support function to help match appMetadata
327
+ * @param environment
328
+ * @param clientId
329
+ */
330
+ getAppMetadataFilteredByInternal(environment, clientId) {
331
+ const allCacheKeys = this.getKeys();
332
+ const matchingAppMetadata = {};
333
+ allCacheKeys.forEach((cacheKey) => {
334
+ // don't parse any non-appMetadata type cache entities
335
+ if (!this.isAppMetadata(cacheKey)) {
336
+ return;
337
+ }
338
+ // Attempt retrieval
339
+ const entity = this.getAppMetadata(cacheKey);
340
+ if (!entity) {
341
+ return;
342
+ }
343
+ if (!!environment && !this.matchEnvironment(entity, environment)) {
344
+ return;
345
+ }
346
+ if (!!clientId && !this.matchClientId(entity, clientId)) {
347
+ return;
348
+ }
349
+ matchingAppMetadata[cacheKey] = entity;
350
+ });
351
+ return matchingAppMetadata;
352
+ }
353
+ /**
354
+ * retrieve authorityMetadata that contains a matching alias
355
+ * @param filter
356
+ */
357
+ getAuthorityMetadataByAlias(host) {
358
+ const allCacheKeys = this.getAuthorityMetadataKeys();
359
+ let matchedEntity = null;
360
+ allCacheKeys.forEach((cacheKey) => {
361
+ // don't parse any non-authorityMetadata type cache entities
362
+ if (!this.isAuthorityMetadata(cacheKey) ||
363
+ cacheKey.indexOf(this.clientId) === -1) {
364
+ return;
365
+ }
366
+ // Attempt retrieval
367
+ const entity = this.getAuthorityMetadata(cacheKey);
368
+ if (!entity) {
369
+ return;
370
+ }
371
+ if (entity.aliases.indexOf(host) === -1) {
372
+ return;
373
+ }
374
+ matchedEntity = entity;
375
+ });
376
+ return matchedEntity;
377
+ }
378
+ /**
379
+ * Removes all accounts and related tokens from cache.
380
+ */
381
+ async removeAllAccounts() {
382
+ const allAccountKeys = this.getAccountKeys();
383
+ const removedAccounts = [];
384
+ allAccountKeys.forEach((cacheKey) => {
385
+ removedAccounts.push(this.removeAccount(cacheKey));
386
+ });
387
+ await Promise.all(removedAccounts);
388
+ }
389
+ /**
390
+ * Removes the account and related tokens for a given account key
391
+ * @param account
392
+ */
393
+ async removeAccount(accountKey) {
394
+ const account = this.getAccount(accountKey);
395
+ if (!account) {
396
+ return;
397
+ }
398
+ await this.removeAccountContext(account);
399
+ this.removeItem(accountKey);
400
+ }
401
+ /**
402
+ * Removes credentials associated with the provided account
403
+ * @param account
404
+ */
405
+ async removeAccountContext(account) {
406
+ const allTokenKeys = this.getTokenKeys();
407
+ const accountId = account.generateAccountId();
408
+ const removedCredentials = [];
409
+ allTokenKeys.idToken.forEach((key) => {
410
+ if (key.indexOf(accountId) === 0) {
411
+ this.removeIdToken(key);
412
+ }
413
+ });
414
+ allTokenKeys.accessToken.forEach((key) => {
415
+ if (key.indexOf(accountId) === 0) {
416
+ removedCredentials.push(this.removeAccessToken(key));
417
+ }
418
+ });
419
+ allTokenKeys.refreshToken.forEach((key) => {
420
+ if (key.indexOf(accountId) === 0) {
421
+ this.removeRefreshToken(key);
422
+ }
423
+ });
424
+ await Promise.all(removedCredentials);
425
+ }
426
+ /**
427
+ * returns a boolean if the given credential is removed
428
+ * @param credential
429
+ */
430
+ async removeAccessToken(key) {
431
+ const credential = this.getAccessTokenCredential(key);
432
+ if (!credential) {
433
+ return;
434
+ }
435
+ // Remove Token Binding Key from key store for PoP Tokens Credentials
436
+ if (credential.credentialType.toLowerCase() ===
437
+ CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME.toLowerCase()) {
438
+ if (credential.tokenType === AuthenticationScheme.POP) {
439
+ const accessTokenWithAuthSchemeEntity = credential;
440
+ const kid = accessTokenWithAuthSchemeEntity.keyId;
441
+ if (kid) {
442
+ try {
443
+ await this.cryptoImpl.removeTokenBindingKey(kid);
444
+ }
445
+ catch (error) {
446
+ throw createClientAuthError(bindingKeyNotRemoved);
447
+ }
448
+ }
449
+ }
450
+ }
451
+ return this.removeItem(key);
452
+ }
453
+ /**
454
+ * Removes all app metadata objects from cache.
455
+ */
456
+ removeAppMetadata() {
457
+ const allCacheKeys = this.getKeys();
458
+ allCacheKeys.forEach((cacheKey) => {
459
+ if (this.isAppMetadata(cacheKey)) {
460
+ this.removeItem(cacheKey);
461
+ }
462
+ });
463
+ return true;
464
+ }
465
+ /**
466
+ * Retrieve the cached credentials into a cacherecord
467
+ * @param account
468
+ * @param clientId
469
+ * @param scopes
470
+ * @param environment
471
+ * @param authScheme
472
+ */
473
+ readCacheRecord(account, request, environment) {
474
+ const tokenKeys = this.getTokenKeys();
475
+ const cachedAccount = this.readAccountFromCache(account);
476
+ const cachedIdToken = this.getIdToken(account, tokenKeys);
477
+ const cachedAccessToken = this.getAccessToken(account, request, tokenKeys);
478
+ const cachedRefreshToken = this.getRefreshToken(account, false, tokenKeys);
479
+ const cachedAppMetadata = this.readAppMetadataFromCache(environment);
480
+ if (cachedAccount && cachedIdToken) {
481
+ cachedAccount.idTokenClaims = extractTokenClaims(cachedIdToken.secret, this.cryptoImpl.base64Decode);
482
+ }
483
+ return {
484
+ account: cachedAccount,
485
+ idToken: cachedIdToken,
486
+ accessToken: cachedAccessToken,
487
+ refreshToken: cachedRefreshToken,
488
+ appMetadata: cachedAppMetadata,
489
+ };
490
+ }
491
+ /**
492
+ * Retrieve AccountEntity from cache
493
+ * @param account
494
+ */
495
+ readAccountFromCache(account) {
496
+ const accountKey = AccountEntity.generateAccountCacheKey(account);
497
+ return this.getAccount(accountKey);
498
+ }
499
+ /**
500
+ * Retrieve IdTokenEntity from cache
501
+ * @param clientId
502
+ * @param account
503
+ * @param inputRealm
504
+ */
505
+ getIdToken(account, tokenKeys) {
506
+ this.commonLogger.trace("CacheManager - getIdToken called");
507
+ const idTokenFilter = {
508
+ homeAccountId: account.homeAccountId,
509
+ environment: account.environment,
510
+ credentialType: CredentialType.ID_TOKEN,
511
+ clientId: this.clientId,
512
+ realm: account.tenantId,
513
+ };
514
+ const idTokens = this.getIdTokensByFilter(idTokenFilter, tokenKeys);
515
+ const numIdTokens = idTokens.length;
516
+ if (numIdTokens < 1) {
517
+ this.commonLogger.info("CacheManager:getIdToken - No token found");
518
+ return null;
519
+ }
520
+ else if (numIdTokens > 1) {
521
+ this.commonLogger.info("CacheManager:getIdToken - Multiple id tokens found, clearing them");
522
+ idTokens.forEach((idToken) => {
523
+ this.removeIdToken(idToken.generateCredentialKey());
524
+ });
525
+ return null;
526
+ }
527
+ this.commonLogger.info("CacheManager:getIdToken - Returning id token");
528
+ return idTokens[0];
529
+ }
530
+ /**
531
+ * Gets all idTokens matching the given filter
532
+ * @param filter
533
+ * @returns
534
+ */
535
+ getIdTokensByFilter(filter, tokenKeys) {
536
+ const idTokenKeys = (tokenKeys && tokenKeys.idToken) || this.getTokenKeys().idToken;
537
+ const idTokens = [];
538
+ idTokenKeys.forEach((key) => {
539
+ if (!this.idTokenKeyMatchesFilter(key, {
540
+ clientId: this.clientId,
541
+ ...filter,
542
+ })) {
543
+ return;
544
+ }
545
+ const idToken = this.getIdTokenCredential(key);
546
+ if (idToken && this.credentialMatchesFilter(idToken, filter)) {
547
+ idTokens.push(idToken);
548
+ }
549
+ });
550
+ return idTokens;
551
+ }
552
+ /**
553
+ * Validate the cache key against filter before retrieving and parsing cache value
554
+ * @param key
555
+ * @param filter
556
+ * @returns
557
+ */
558
+ idTokenKeyMatchesFilter(inputKey, filter) {
559
+ const key = inputKey.toLowerCase();
560
+ if (filter.clientId &&
561
+ key.indexOf(filter.clientId.toLowerCase()) === -1) {
562
+ return false;
563
+ }
564
+ if (filter.homeAccountId &&
565
+ key.indexOf(filter.homeAccountId.toLowerCase()) === -1) {
566
+ return false;
567
+ }
568
+ return true;
569
+ }
570
+ /**
571
+ * Removes idToken from the cache
572
+ * @param key
573
+ */
574
+ removeIdToken(key) {
575
+ this.removeItem(key);
576
+ }
577
+ /**
578
+ * Removes refresh token from the cache
579
+ * @param key
580
+ */
581
+ removeRefreshToken(key) {
582
+ this.removeItem(key);
583
+ }
584
+ /**
585
+ * Retrieve AccessTokenEntity from cache
586
+ * @param clientId
587
+ * @param account
588
+ * @param scopes
589
+ * @param authScheme
590
+ */
591
+ getAccessToken(account, request, tokenKeys) {
592
+ this.commonLogger.trace("CacheManager - getAccessToken called");
593
+ const scopes = ScopeSet.createSearchScopes(request.scopes);
594
+ const authScheme = request.authenticationScheme || AuthenticationScheme.BEARER;
595
+ /*
596
+ * Distinguish between Bearer and PoP/SSH token cache types
597
+ * Cast to lowercase to handle "bearer" from ADFS
598
+ */
599
+ const credentialType = authScheme &&
600
+ authScheme.toLowerCase() !==
601
+ AuthenticationScheme.BEARER.toLowerCase()
602
+ ? CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME
603
+ : CredentialType.ACCESS_TOKEN;
604
+ const accessTokenFilter = {
605
+ homeAccountId: account.homeAccountId,
606
+ environment: account.environment,
607
+ credentialType: credentialType,
608
+ clientId: this.clientId,
609
+ realm: account.tenantId,
610
+ target: scopes,
611
+ tokenType: authScheme,
612
+ keyId: request.sshKid,
613
+ requestedClaimsHash: request.requestedClaimsHash,
614
+ };
615
+ const accessTokenKeys = (tokenKeys && tokenKeys.accessToken) ||
616
+ this.getTokenKeys().accessToken;
617
+ const accessTokens = [];
618
+ accessTokenKeys.forEach((key) => {
619
+ // Validate key
620
+ if (this.accessTokenKeyMatchesFilter(key, accessTokenFilter, true)) {
621
+ const accessToken = this.getAccessTokenCredential(key);
622
+ // Validate value
623
+ if (accessToken &&
624
+ this.credentialMatchesFilter(accessToken, accessTokenFilter)) {
625
+ accessTokens.push(accessToken);
626
+ }
627
+ }
628
+ });
629
+ const numAccessTokens = accessTokens.length;
630
+ if (numAccessTokens < 1) {
631
+ this.commonLogger.info("CacheManager:getAccessToken - No token found");
632
+ return null;
633
+ }
634
+ else if (numAccessTokens > 1) {
635
+ this.commonLogger.info("CacheManager:getAccessToken - Multiple access tokens found, clearing them");
636
+ accessTokens.forEach((accessToken) => {
637
+ void this.removeAccessToken(accessToken.generateCredentialKey());
638
+ });
639
+ return null;
640
+ }
641
+ this.commonLogger.info("CacheManager:getAccessToken - Returning access token");
642
+ return accessTokens[0];
643
+ }
644
+ /**
645
+ * Validate the cache key against filter before retrieving and parsing cache value
646
+ * @param key
647
+ * @param filter
648
+ * @param keyMustContainAllScopes
649
+ * @returns
650
+ */
651
+ accessTokenKeyMatchesFilter(inputKey, filter, keyMustContainAllScopes) {
652
+ const key = inputKey.toLowerCase();
653
+ if (filter.clientId &&
654
+ key.indexOf(filter.clientId.toLowerCase()) === -1) {
655
+ return false;
656
+ }
657
+ if (filter.homeAccountId &&
658
+ key.indexOf(filter.homeAccountId.toLowerCase()) === -1) {
659
+ return false;
660
+ }
661
+ if (filter.realm && key.indexOf(filter.realm.toLowerCase()) === -1) {
662
+ return false;
663
+ }
664
+ if (filter.requestedClaimsHash &&
665
+ key.indexOf(filter.requestedClaimsHash.toLowerCase()) === -1) {
666
+ return false;
667
+ }
668
+ if (filter.target) {
669
+ const scopes = filter.target.asArray();
670
+ for (let i = 0; i < scopes.length; i++) {
671
+ if (keyMustContainAllScopes &&
672
+ !key.includes(scopes[i].toLowerCase())) {
673
+ // When performing a cache lookup a missing scope would be a cache miss
674
+ return false;
675
+ }
676
+ else if (!keyMustContainAllScopes &&
677
+ key.includes(scopes[i].toLowerCase())) {
678
+ // When performing a cache write, any token with a subset of requested scopes should be replaced
679
+ return true;
680
+ }
681
+ }
682
+ }
683
+ return true;
684
+ }
685
+ /**
686
+ * Gets all access tokens matching the filter
687
+ * @param filter
688
+ * @returns
689
+ */
690
+ getAccessTokensByFilter(filter) {
691
+ const tokenKeys = this.getTokenKeys();
692
+ const accessTokens = [];
693
+ tokenKeys.accessToken.forEach((key) => {
694
+ if (!this.accessTokenKeyMatchesFilter(key, filter, true)) {
695
+ return;
696
+ }
697
+ const accessToken = this.getAccessTokenCredential(key);
698
+ if (accessToken &&
699
+ this.credentialMatchesFilter(accessToken, filter)) {
700
+ accessTokens.push(accessToken);
701
+ }
702
+ });
703
+ return accessTokens;
704
+ }
705
+ /**
706
+ * Helper to retrieve the appropriate refresh token from cache
707
+ * @param clientId
708
+ * @param account
709
+ * @param familyRT
710
+ */
711
+ getRefreshToken(account, familyRT, tokenKeys) {
712
+ this.commonLogger.trace("CacheManager - getRefreshToken called");
713
+ const id = familyRT ? THE_FAMILY_ID : undefined;
714
+ const refreshTokenFilter = {
715
+ homeAccountId: account.homeAccountId,
716
+ environment: account.environment,
717
+ credentialType: CredentialType.REFRESH_TOKEN,
718
+ clientId: this.clientId,
719
+ familyId: id,
720
+ };
721
+ const refreshTokenKeys = (tokenKeys && tokenKeys.refreshToken) ||
722
+ this.getTokenKeys().refreshToken;
723
+ const refreshTokens = [];
724
+ refreshTokenKeys.forEach((key) => {
725
+ // Validate key
726
+ if (this.refreshTokenKeyMatchesFilter(key, refreshTokenFilter)) {
727
+ const refreshToken = this.getRefreshTokenCredential(key);
728
+ // Validate value
729
+ if (refreshToken &&
730
+ this.credentialMatchesFilter(refreshToken, refreshTokenFilter)) {
731
+ refreshTokens.push(refreshToken);
732
+ }
733
+ }
734
+ });
735
+ const numRefreshTokens = refreshTokens.length;
736
+ if (numRefreshTokens < 1) {
737
+ this.commonLogger.info("CacheManager:getRefreshToken - No refresh token found.");
738
+ return null;
739
+ }
740
+ // address the else case after remove functions address environment aliases
741
+ this.commonLogger.info("CacheManager:getRefreshToken - returning refresh token");
742
+ return refreshTokens[0];
743
+ }
744
+ /**
745
+ * Validate the cache key against filter before retrieving and parsing cache value
746
+ * @param key
747
+ * @param filter
748
+ */
749
+ refreshTokenKeyMatchesFilter(inputKey, filter) {
750
+ const key = inputKey.toLowerCase();
751
+ if (filter.familyId &&
752
+ key.indexOf(filter.familyId.toLowerCase()) === -1) {
753
+ return false;
754
+ }
755
+ // If familyId is used, clientId is not in the key
756
+ if (!filter.familyId &&
757
+ filter.clientId &&
758
+ key.indexOf(filter.clientId.toLowerCase()) === -1) {
759
+ return false;
760
+ }
761
+ if (filter.homeAccountId &&
762
+ key.indexOf(filter.homeAccountId.toLowerCase()) === -1) {
763
+ return false;
764
+ }
765
+ return true;
766
+ }
767
+ /**
768
+ * Retrieve AppMetadataEntity from cache
769
+ */
770
+ readAppMetadataFromCache(environment) {
771
+ const appMetadataFilter = {
772
+ environment,
773
+ clientId: this.clientId,
774
+ };
775
+ const appMetadata = this.getAppMetadataFilteredBy(appMetadataFilter);
776
+ const appMetadataEntries = Object.keys(appMetadata).map((key) => appMetadata[key]);
777
+ const numAppMetadata = appMetadataEntries.length;
778
+ if (numAppMetadata < 1) {
779
+ return null;
780
+ }
781
+ else if (numAppMetadata > 1) {
782
+ throw createClientAuthError(multipleMatchingAppMetadata);
783
+ }
784
+ return appMetadataEntries[0];
785
+ }
786
+ /**
787
+ * Return the family_id value associated with FOCI
788
+ * @param environment
789
+ * @param clientId
790
+ */
791
+ isAppMetadataFOCI(environment) {
792
+ const appMetadata = this.readAppMetadataFromCache(environment);
793
+ return !!(appMetadata && appMetadata.familyId === THE_FAMILY_ID);
794
+ }
795
+ /**
796
+ * helper to match account ids
797
+ * @param value
798
+ * @param homeAccountId
799
+ */
800
+ matchHomeAccountId(entity, homeAccountId) {
801
+ return !!(typeof entity.homeAccountId === "string" &&
802
+ homeAccountId === entity.homeAccountId);
803
+ }
804
+ /**
805
+ * helper to match account ids
806
+ * @param entity
807
+ * @param localAccountId
808
+ * @returns
809
+ */
810
+ matchLocalAccountId(entity, localAccountId) {
811
+ return !!(typeof entity.localAccountId === "string" &&
812
+ localAccountId === entity.localAccountId);
813
+ }
814
+ /**
815
+ * helper to match usernames
816
+ * @param entity
817
+ * @param username
818
+ * @returns
819
+ */
820
+ matchUsername(entity, username) {
821
+ return !!(typeof entity.username === "string" &&
822
+ username.toLowerCase() === entity.username.toLowerCase());
823
+ }
824
+ /**
825
+ * helper to match names
826
+ * @param entity
827
+ * @param name
828
+ * @returns true if the downcased name properties are present and match in the filter and the entity
829
+ */
830
+ matchName(entity, name) {
831
+ return !!(name.toLowerCase() === entity.name?.toLowerCase());
832
+ }
833
+ /**
834
+ * helper to match assertion
835
+ * @param value
836
+ * @param oboAssertion
837
+ */
838
+ matchUserAssertionHash(entity, userAssertionHash) {
839
+ return !!(entity.userAssertionHash &&
840
+ userAssertionHash === entity.userAssertionHash);
841
+ }
842
+ /**
843
+ * helper to match environment
844
+ * @param value
845
+ * @param environment
846
+ */
847
+ matchEnvironment(entity, environment) {
848
+ const cloudMetadata = this.getAuthorityMetadataByAlias(environment);
849
+ if (cloudMetadata &&
850
+ cloudMetadata.aliases.indexOf(entity.environment) > -1) {
851
+ return true;
852
+ }
853
+ return false;
854
+ }
855
+ /**
856
+ * helper to match credential type
857
+ * @param entity
858
+ * @param credentialType
859
+ */
860
+ matchCredentialType(entity, credentialType) {
861
+ return (entity.credentialType &&
862
+ credentialType.toLowerCase() === entity.credentialType.toLowerCase());
863
+ }
864
+ /**
865
+ * helper to match client ids
866
+ * @param entity
867
+ * @param clientId
868
+ */
869
+ matchClientId(entity, clientId) {
870
+ return !!(entity.clientId && clientId === entity.clientId);
871
+ }
872
+ /**
873
+ * helper to match family ids
874
+ * @param entity
875
+ * @param familyId
876
+ */
877
+ matchFamilyId(entity, familyId) {
878
+ return !!(entity.familyId && familyId === entity.familyId);
879
+ }
880
+ /**
881
+ * helper to match realm
882
+ * @param entity
883
+ * @param realm
884
+ */
885
+ matchRealm(entity, realm) {
886
+ return !!(entity.realm && realm === entity.realm);
887
+ }
888
+ /**
889
+ * helper to match nativeAccountId
890
+ * @param entity
891
+ * @param nativeAccountId
892
+ * @returns boolean indicating the match result
893
+ */
894
+ matchNativeAccountId(entity, nativeAccountId) {
895
+ return !!(entity.nativeAccountId && nativeAccountId === entity.nativeAccountId);
896
+ }
897
+ /**
898
+ * helper to match loginHint which can be either:
899
+ * 1. login_hint ID token claim
900
+ * 2. username in cached account object
901
+ * 3. upn in ID token claims
902
+ * @param entity
903
+ * @param loginHint
904
+ * @returns
905
+ */
906
+ matchLoginHint(entity, loginHint) {
907
+ if (entity.idTokenClaims?.login_hint === loginHint) {
908
+ return true;
909
+ }
910
+ if (entity.username === loginHint) {
911
+ return true;
912
+ }
913
+ if (entity.idTokenClaims?.upn === loginHint) {
914
+ return true;
915
+ }
916
+ return false;
917
+ }
918
+ matchAuthorityType(entity, authorityType) {
919
+ return !!(entity.authorityType &&
920
+ authorityType.toLowerCase() === entity.authorityType.toLowerCase());
921
+ }
922
+ /**
923
+ * Returns true if the target scopes are a subset of the current entity's scopes, false otherwise.
924
+ * @param entity
925
+ * @param target
926
+ */
927
+ matchTarget(entity, target) {
928
+ const isNotAccessTokenCredential = entity.credentialType !== CredentialType.ACCESS_TOKEN &&
929
+ entity.credentialType !==
930
+ CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME;
931
+ if (isNotAccessTokenCredential || !entity.target) {
932
+ return false;
933
+ }
934
+ const entityScopeSet = ScopeSet.fromString(entity.target);
935
+ return entityScopeSet.containsScopeSet(target);
936
+ }
937
+ /**
938
+ * Returns true if the credential's tokenType or Authentication Scheme matches the one in the request, false otherwise
939
+ * @param entity
940
+ * @param tokenType
941
+ */
942
+ matchTokenType(entity, tokenType) {
943
+ return !!(entity.tokenType && entity.tokenType === tokenType);
944
+ }
945
+ /**
946
+ * Returns true if the credential's keyId matches the one in the request, false otherwise
947
+ * @param entity
948
+ * @param tokenType
949
+ */
950
+ matchKeyId(entity, keyId) {
951
+ return !!(entity.keyId && entity.keyId === keyId);
952
+ }
953
+ /**
954
+ * returns if a given cache entity is of the type appmetadata
955
+ * @param key
956
+ */
957
+ isAppMetadata(key) {
958
+ return key.indexOf(APP_METADATA) !== -1;
959
+ }
960
+ /**
961
+ * returns if a given cache entity is of the type authoritymetadata
962
+ * @param key
963
+ */
964
+ isAuthorityMetadata(key) {
965
+ return key.indexOf(AUTHORITY_METADATA_CONSTANTS.CACHE_KEY) !== -1;
966
+ }
967
+ /**
968
+ * returns cache key used for cloud instance metadata
969
+ */
970
+ generateAuthorityMetadataCacheKey(authority) {
971
+ return `${AUTHORITY_METADATA_CONSTANTS.CACHE_KEY}-${this.clientId}-${authority}`;
972
+ }
973
+ /**
974
+ * Helper to convert serialized data to object
975
+ * @param obj
976
+ * @param json
977
+ */
978
+ static toObject(obj, json) {
979
+ for (const propertyName in json) {
980
+ obj[propertyName] = json[propertyName];
981
+ }
982
+ return obj;
983
+ }
984
+ }
985
+ /** @internal */
986
+ class DefaultStorageClass extends CacheManager {
987
+ setAccount() {
988
+ throw createClientAuthError(methodNotImplemented);
989
+ }
990
+ getAccount() {
991
+ throw createClientAuthError(methodNotImplemented);
992
+ }
993
+ setIdTokenCredential() {
994
+ throw createClientAuthError(methodNotImplemented);
995
+ }
996
+ getIdTokenCredential() {
997
+ throw createClientAuthError(methodNotImplemented);
998
+ }
999
+ setAccessTokenCredential() {
1000
+ throw createClientAuthError(methodNotImplemented);
1001
+ }
1002
+ getAccessTokenCredential() {
1003
+ throw createClientAuthError(methodNotImplemented);
1004
+ }
1005
+ setRefreshTokenCredential() {
1006
+ throw createClientAuthError(methodNotImplemented);
1007
+ }
1008
+ getRefreshTokenCredential() {
1009
+ throw createClientAuthError(methodNotImplemented);
1010
+ }
1011
+ setAppMetadata() {
1012
+ throw createClientAuthError(methodNotImplemented);
1013
+ }
1014
+ getAppMetadata() {
1015
+ throw createClientAuthError(methodNotImplemented);
1016
+ }
1017
+ setServerTelemetry() {
1018
+ throw createClientAuthError(methodNotImplemented);
1019
+ }
1020
+ getServerTelemetry() {
1021
+ throw createClientAuthError(methodNotImplemented);
1022
+ }
1023
+ setAuthorityMetadata() {
1024
+ throw createClientAuthError(methodNotImplemented);
1025
+ }
1026
+ getAuthorityMetadata() {
1027
+ throw createClientAuthError(methodNotImplemented);
1028
+ }
1029
+ getAuthorityMetadataKeys() {
1030
+ throw createClientAuthError(methodNotImplemented);
1031
+ }
1032
+ setThrottlingCache() {
1033
+ throw createClientAuthError(methodNotImplemented);
1034
+ }
1035
+ getThrottlingCache() {
1036
+ throw createClientAuthError(methodNotImplemented);
1037
+ }
1038
+ removeItem() {
1039
+ throw createClientAuthError(methodNotImplemented);
1040
+ }
1041
+ containsKey() {
1042
+ throw createClientAuthError(methodNotImplemented);
1043
+ }
1044
+ getKeys() {
1045
+ throw createClientAuthError(methodNotImplemented);
1046
+ }
1047
+ getAccountKeys() {
1048
+ throw createClientAuthError(methodNotImplemented);
1049
+ }
1050
+ getTokenKeys() {
1051
+ throw createClientAuthError(methodNotImplemented);
1052
+ }
1053
+ async clear() {
1054
+ throw createClientAuthError(methodNotImplemented);
1055
+ }
1056
+ updateCredentialCacheKey() {
1057
+ throw createClientAuthError(methodNotImplemented);
1058
+ }
1008
1059
  }
1009
1060
 
1010
1061
  export { CacheManager, DefaultStorageClass };