Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Multi-tenant accounts and cross-tenant token caching #6536

Merged
merged 124 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
124 commits
Select commit Hold shift + click to select a range
33d94a6
Remove ID token claims from account entity before caching
hectormmg Sep 30, 2023
8b7e6ad
Refactor getAllAccounts to remove duplicated logic
hectormmg Sep 30, 2023
13b2f8b
Persist authority metadata in temporary cache to make it available fo…
hectormmg Oct 1, 2023
4c1f845
Update getAccount APIs to only return accounts if there's a matching …
hectormmg Oct 1, 2023
9ea89fd
Update tests to reflect authority metadata caching changes
hectormmg Oct 1, 2023
14a1181
Merge branch 'dev' into cached-account-change
hectormmg Oct 3, 2023
d747689
Revert authority metadata storage to in-memory cache and add a synchr…
hectormmg Oct 3, 2023
dd78466
Merge branch 'dev' into cached-account-change
hectormmg Oct 3, 2023
6149773
Change files
hectormmg Oct 3, 2023
1c73768
Remove unused authority metadata removal method
hectormmg Oct 3, 2023
efdfff0
Remove unused method from cachemanager
hectormmg Oct 3, 2023
2f35887
Load local authority metadata in MSAL Node PCA
hectormmg Oct 3, 2023
1b53577
Change files
hectormmg Oct 3, 2023
dbc7d8c
Add multi-tenant sample
hectormmg Oct 3, 2023
6e964e2
Update change/@azure-msal-node-695c255d-9b72-4c81-b93a-886e651da57a.json
hectormmg Oct 4, 2023
2888e74
Add support for cross-tenant token caching and multi-tenant accounts
hectormmg Oct 4, 2023
a4cad18
Merge branch 'cached-account-change' into enable-multi-tenant
hectormmg Oct 4, 2023
774603e
Merge branch 'dev' into cached-account-change
hectormmg Oct 4, 2023
2acc32d
Update getAccount API tests to use test ID token secrets instead of a…
hectormmg Oct 5, 2023
a28dab5
Update tests to reflect account caching changes for multi-tenant support
hectormmg Oct 5, 2023
3ba2016
Merge branch 'enable-multi-tenant' of github.com:AzureAD/microsoft-au…
hectormmg Oct 5, 2023
de492e1
Merge branch 'cached-account-change' into enable-multi-tenant
hectormmg Oct 5, 2023
48b8ed7
Update multi-tenant sample
hectormmg Oct 5, 2023
d3361b6
Merge branch 'dev' into cached-account-change
hectormmg Oct 5, 2023
f61a563
Merge branch 'dev' into cached-account-change
hectormmg Oct 6, 2023
1c1b582
Use static authority options from configuration and hardcoded metadat…
hectormmg Oct 9, 2023
2f7621c
Update lib/msal-browser/test/interaction_client/BaseInteractionClient…
hectormmg Oct 10, 2023
69ebbea
Refactor active account logic and native account lookup
hectormmg Oct 10, 2023
84c69c2
Merge branch 'dev' into cached-account-change
hectormmg Oct 10, 2023
c7ffc41
Fix cloud discovery metadata static config processing
hectormmg Oct 11, 2023
fff6198
Make sure id token claims are excluded from accounts to be cached but…
hectormmg Oct 11, 2023
7fff7fc
Clean up static authority options code
hectormmg Oct 11, 2023
aacea06
Undo pre-caching idtokenclaims removal for accounts
hectormmg Oct 11, 2023
5a40a66
Update lib/msal-common/src/response/ResponseHandler.ts
hectormmg Oct 11, 2023
9001cee
Add environment filtering tests with static metadata and refactor res…
hectormmg Oct 11, 2023
129b96f
Merge branch 'cached-account-change' of github.com:AzureAD/microsoft-…
hectormmg Oct 11, 2023
13ba16d
Merge branch 'dev' into cached-account-change
hectormmg Oct 11, 2023
ebdbacc
Merge branch 'cached-account-change' into enable-multi-tenant
hectormmg Oct 12, 2023
9f9af08
Add tenant list assignment to AccountEntity.createFromAccountInfo
hectormmg Oct 12, 2023
08111cd
Update node serialization/deserialization to include tenants list
hectormmg Oct 12, 2023
ad67c66
Factor out getTenantFromAuthorityString into an exported function
hectormmg Oct 12, 2023
6f50405
Fix mock client info parsing in node ClientTestUtils
hectormmg Oct 12, 2023
8273740
Update node storage tests with new test cache keys
hectormmg Oct 12, 2023
223cab9
Update Node PCA tests
hectormmg Oct 12, 2023
54aa44c
Merge branch 'dev' into enable-multi-tenant
hectormmg Oct 12, 2023
f785dc1
Merge branch 'dev' into enable-multi-tenant
hectormmg Oct 12, 2023
835e32f
Remove idTokenClaims from AccountEntity since ID token claims are not…
hectormmg Oct 12, 2023
b81b818
Make tenantId optional in active account filters
hectormmg Oct 12, 2023
b3ded6f
Add account cache update from single tenant to multi-tenant
hectormmg Oct 13, 2023
140295e
Add outdated (single-tenant) account update logic when cached account…
hectormmg Oct 13, 2023
d508aa8
Address PR feedback
hectormmg Oct 13, 2023
fc7b14d
Address PR feedback
hectormmg Oct 13, 2023
191ef0b
Fix B2C ID token matching by removing account tenantId from ID token …
hectormmg Oct 13, 2023
d805248
Merge branch 'dev' into enable-multi-tenant
hectormmg Oct 16, 2023
d517757
Merge branch 'dev' into enable-multi-tenant
hectormmg Oct 16, 2023
6f6fda9
Change files
hectormmg Oct 16, 2023
e58470a
Fix B2C and named tenant cross-tenant caching and lookup
hectormmg Oct 24, 2023
0cfe01e
Update common unit tests
hectormmg Oct 24, 2023
dda7588
Update common, browser and node unit tests
hectormmg Oct 24, 2023
142be3a
Merge branch 'dev' into enable-multi-tenant
hectormmg Oct 24, 2023
af6130b
Update browser cache test utils to use utid from idToken homeAccountI…
hectormmg Oct 24, 2023
6554303
Add ID token duplicate removal logic
hectormmg Oct 25, 2023
d35b27d
Merge branch 'dev' into enable-multi-tenant
hectormmg Oct 31, 2023
276d2bd
Set sample to localstorage
hectormmg Oct 31, 2023
41be4ae
Merge branch 'dev' into enable-multi-tenant
hectormmg Nov 6, 2023
f9d1797
Add tenant profile maps
hectormmg Nov 8, 2023
99d45a7
Merge branch 'dev' into enable-multi-tenant
hectormmg Nov 8, 2023
8894041
Add migration logic from single-tenant to multi-tenant account entities
hectormmg Nov 8, 2023
ec1d5ae
Merge branch 'dev' into enable-multi-tenant
hectormmg Nov 8, 2023
f9dae3c
Update account APIs to return all tenant profiles as overriden accoun…
hectormmg Nov 12, 2023
15162ca
Update common tests
hectormmg Nov 12, 2023
4a6a186
Merge branch 'enable-multi-tenant' of github.com:AzureAD/microsoft-au…
hectormmg Nov 12, 2023
587a9e1
Merge branch 'dev' into enable-multi-tenant
hectormmg Nov 12, 2023
90f6e02
Factor setCachedAccount out into an exported function in ResponseHand…
hectormmg Nov 13, 2023
572c28d
Update msal-node to use tenantProfiles in serialization instead of te…
hectormmg Nov 13, 2023
c9e8a18
Replace encoding test constants
hectormmg Nov 13, 2023
6721a3a
Prettify test cache file
hectormmg Nov 13, 2023
3ea2dd8
Fix b2c tests by using msal-node serializer instead of outdated e2e-t…
hectormmg Nov 13, 2023
877ad7e
Merge branch 'dev' into enable-multi-tenant
hectormmg Nov 13, 2023
be6b7ab
Add tests for Authority Utility functions
hectormmg Nov 14, 2023
bf45c12
Increase test coverage in CacheManager
hectormmg Nov 14, 2023
01d3793
Add TokenClaims utilties tests
hectormmg Nov 14, 2023
3a62e4e
Increase test coverage for AccountEntity
hectormmg Nov 14, 2023
932594c
Add multi-tenant docs first draft
hectormmg Nov 14, 2023
17301aa
Update multi-tenant docs
hectormmg Nov 14, 2023
662b20a
Add multi-tenant reference to node and browser docs
hectormmg Nov 14, 2023
09a95af
Merge branch 'dev' into enable-multi-tenant
hectormmg Nov 14, 2023
30b4488
Update lib/msal-browser/test/cache/TestStorageManager.ts
hectormmg Nov 15, 2023
82dc1e9
Address PR feedback
hectormmg Nov 15, 2023
8c35085
Merge branch 'enable-multi-tenant' of github.com:AzureAD/microsoft-au…
hectormmg Nov 15, 2023
d609c6f
Update base64Decode in buildClientInfo usages
hectormmg Nov 15, 2023
2e09ae5
Fix formatting
hectormmg Nov 15, 2023
d17fc59
Update docs
hectormmg Nov 15, 2023
e24ce71
Update lib/msal-common/docs/multi-tenant-accounts.md
hectormmg Nov 15, 2023
fda2f57
Update multi-tenant docs from feedback
hectormmg Nov 16, 2023
df39511
Merge branch 'enable-multi-tenant' of github.com:AzureAD/microsoft-au…
hectormmg Nov 16, 2023
e77b98a
Merge branch 'dev' into enable-multi-tenant
hectormmg Nov 16, 2023
f2a21de
Address PR feedback
hectormmg Nov 16, 2023
1c3d33e
Merge branch 'enable-multi-tenant' of github.com:AzureAD/microsoft-au…
hectormmg Nov 16, 2023
c2038db
Merge branch 'dev' into enable-multi-tenant
hectormmg Nov 20, 2023
4b1bf37
Update multi-tenant account docs
hectormmg Nov 22, 2023
c3bb735
Replace cryptoObj.base64Decode with original base64Decode function
hectormmg Nov 22, 2023
585b9e3
Merge branch 'enable-multi-tenant' of github.com:AzureAD/microsoft-au…
hectormmg Nov 22, 2023
36c9f1a
Add multi-tenant e2e tests
hectormmg Nov 23, 2023
78b5d9a
Update test utils
hectormmg Nov 23, 2023
8a8623c
Remove multi-tenant sample app
hectormmg Nov 23, 2023
fe405c4
Update browser cache test utils to ignore pop tokens in accessTokenFo…
hectormmg Nov 23, 2023
0ff394c
Hide http request log in VanillaJSTestApp when running customizable-e…
hectormmg Nov 23, 2023
d873cbf
Fix realm matching logic in CacheManager
hectormmg Nov 23, 2023
75c576a
Update customizable-e2e-sample to use activeAccount
hectormmg Nov 23, 2023
9e476fb
Refactor verifyTokenStore browser cache util
hectormmg Nov 24, 2023
21ac601
Fix multi-tenant e2e tests
hectormmg Nov 24, 2023
cbc4454
Fix BrowserCacheTestUtils typing
hectormmg Nov 24, 2023
3465668
Update test utils to avoid undefined assignments
hectormmg Nov 24, 2023
a9afc38
Update test utils
hectormmg Nov 24, 2023
6ad097f
Fix ignorable ts error in BrowserCacheTestUtils
hectormmg Nov 24, 2023
d65cbeb
Fix browser cache test utils for angular e2e
hectormmg Nov 24, 2023
662cd52
Use check-latest on setup node
hectormmg Nov 27, 2023
f2f3519
Move account and ID token creation test utils to a shared-test-utils dir
hectormmg Nov 28, 2023
900155a
Add shared msal config package
hectormmg Nov 28, 2023
d452fb0
Merge branch 'dev' into enable-multi-tenant
hectormmg Nov 28, 2023
e27fff7
Add shared-utils to workspaces
hectormmg Nov 28, 2023
8363d22
Update package-lock
hectormmg Nov 28, 2023
561f8e7
Merge branch 'dev' into enable-multi-tenant
hectormmg Nov 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Add support for Multi-tenant accounts and cross-tenant token caching #6466",
"packageName": "@azure/msal-browser",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Add support for Multi-tenant accounts and cross-tenant token caching #6466",
"packageName": "@azure/msal-common",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Add support for Multi-tenant accounts and cross-tenant token caching #6466",
"packageName": "@azure/msal-node",
"email": "[email protected]",
"dependentChangeType": "patch"
}
2 changes: 1 addition & 1 deletion lib/msal-browser/docs/accounts.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Accounts in MSAL Browser

> This is the platform-specific Accounts documentation for `@azure/msal-browser`. For the general documentation of the `AccountInfo` object structure, please visit the `@azure/msal-common` [Accounts document](../../msal-common/docs/Accounts.md).
> This is the platform-specific Accounts documentation for `@azure/msal-browser`. For the general documentation of the `AccountInfo` object structure, please visit the `@azure/msal-common` [Accounts document](../../msal-common/docs/Accounts.md). For documentation relating to multi-tenant accounts, please visit the [Multi-tenant Accounts document](../../msal-common/docs/multi-tenant-accounts.md).

## Usage

Expand Down
1 change: 1 addition & 0 deletions lib/msal-browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"@types/sinon": "^7.5.0",
"dotenv": "^8.2.0",
"eslint-config-msal": "^0.0.0",
"msal-test-utils": "^0.0.1",
"fake-indexeddb": "^3.1.3",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
Expand Down
35 changes: 31 additions & 4 deletions lib/msal-browser/src/cache/BrowserCacheManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,15 +394,31 @@ export class BrowserCacheManager extends CacheManager {
* fetch the account entity from the platform cache
* @param accountKey
*/
getAccount(accountKey: string): AccountEntity | null {
getAccount(accountKey: string, logger?: Logger): AccountEntity | null {
this.logger.trace("BrowserCacheManager.getAccount called");
const account = this.getItem(accountKey);
if (!account) {
const accountEntity = this.getCachedAccountEntity(accountKey);

return this.updateOutdatedCachedAccount(
accountKey,
accountEntity,
logger
);
}

/**
* Reads account from cache, deserializes it into an account entity and returns it.
* If account is not found from the key, returns null and removes key from map.
* @param accountKey
* @returns
*/
getCachedAccountEntity(accountKey: string): AccountEntity | null {
const serializedAccount = this.getItem(accountKey);
if (!serializedAccount) {
this.removeAccountKeyFromMap(accountKey);
return null;
}

const parsedAccount = this.validateAndParseJson(account);
const parsedAccount = this.validateAndParseJson(serializedAccount);
if (!parsedAccount || !AccountEntity.isAccountEntity(parsedAccount)) {
this.removeAccountKeyFromMap(accountKey);
return null;
Expand Down Expand Up @@ -505,6 +521,15 @@ export class BrowserCacheManager extends CacheManager {
this.removeAccountKeyFromMap(key);
}

/**
* Remove account entity from the platform cache if it's outdated
* @param accountKey
*/
removeOutdatedAccount(accountKey: string): void {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use the existing removeAccount API instead? Should do the same things

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately that method is async and also removes all tokens related to the account context, I'll try to find a way to factor out the part that removes the account object only.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thats right ok. Nvm this can stay.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename it to removeAccountOnly() as a sync function and call it inside removeAccount? Can be done later, I think that is viable and removes code duplicity

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name is fine. Just reusing is what I want to focus on.

this.removeItem(accountKey);
this.removeAccountKeyFromMap(accountKey);
}

/**
* Removes given idToken from the cache and from the key map
* @param key
Expand Down Expand Up @@ -1034,6 +1059,7 @@ export class BrowserCacheManager extends CacheManager {
return this.getAccountInfoFilteredBy({
homeAccountId: activeAccountValueObj.homeAccountId,
localAccountId: activeAccountValueObj.localAccountId,
tenantId: activeAccountValueObj.tenantId,
});
}
this.logger.trace(
Expand All @@ -1058,6 +1084,7 @@ export class BrowserCacheManager extends CacheManager {
const activeAccountValue: ActiveAccountFilters = {
homeAccountId: account.homeAccountId,
localAccountId: account.localAccountId,
tenantId: account.tenantId,
};
this.browserStorage.setItem(
activeAccountKey,
Expand Down
62 changes: 33 additions & 29 deletions lib/msal-browser/src/cache/TokenCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
CacheRecord,
TokenClaims,
CacheHelpers,
buildAccountToCache,
} from "@azure/msal-common";
import { BrowserConfiguration } from "../config/Configuration";
import { SilentRequest } from "../request/SilentRequest";
Expand Down Expand Up @@ -240,40 +241,43 @@ export class TokenCache implements ITokenCache {
clientInfo?: string,
requestHomeAccountId?: string
): AccountEntity {
let homeAccountId;
if (requestHomeAccountId) {
homeAccountId = requestHomeAccountId;
} else if (authority.authorityType !== undefined && clientInfo) {
homeAccountId = AccountEntity.generateHomeAccountId(
clientInfo,
authority.authorityType,
this.logger,
this.cryptoObj,
idTokenClaims
);
}
if (this.isBrowserEnvironment) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the check up here before all the work is done instead of checking after building the account and then throwing

this.logger.verbose("TokenCache - loading account");
let homeAccountId;
if (requestHomeAccountId) {
homeAccountId = requestHomeAccountId;
} else if (authority.authorityType !== undefined && clientInfo) {
homeAccountId = AccountEntity.generateHomeAccountId(
clientInfo,
authority.authorityType,
this.logger,
this.cryptoObj,
idTokenClaims
);
}

if (!homeAccountId) {
throw createBrowserAuthError(
BrowserAuthErrorCodes.unableToLoadToken
);
}
if (!homeAccountId) {
throw createBrowserAuthError(
BrowserAuthErrorCodes.unableToLoadToken
);
}
const claimsTenantId = idTokenClaims.tid;

const accountEntity = AccountEntity.createAccount(
{
const cachedAccount = buildAccountToCache(
this.storage,
authority,
homeAccountId,
idTokenClaims: idTokenClaims,
idTokenClaims,
base64Decode,
clientInfo,
environment: authority.hostnameAndPort,
},
authority
);

if (this.isBrowserEnvironment) {
this.logger.verbose("TokenCache - loading account");
claimsTenantId,
undefined,
undefined,
this.logger
);

this.storage.setAccount(accountEntity);
return accountEntity;
this.storage.setAccount(cachedAccount);
return cachedAccount;
} else {
throw createBrowserAuthError(
BrowserAuthErrorCodes.unableToLoadToken
Expand Down
2 changes: 1 addition & 1 deletion lib/msal-browser/src/controllers/StandardController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1549,7 +1549,7 @@ export class StandardController implements IController {
): string {
const account =
request.account ||
this.browserStorage.getAccountInfoFilteredBy({
this.getAccount({
loginHint: request.loginHint,
sid: request.sid,
}) ||
Expand Down
1 change: 1 addition & 0 deletions lib/msal-browser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export {
PerformanceEvents,
// Telemetry
InProgressPerformanceEvent,
TenantProfile,
} from "@azure/msal-common";

export { version } from "./packageMetadata";
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ import {
invokeAsync,
createAuthError,
AuthErrorCodes,
updateAccountTenantProfileData,
CacheHelpers,
buildAccountToCache,
} from "@azure/msal-common";
import { BaseInteractionClient } from "./BaseInteractionClient";
import { BrowserConfiguration } from "../config/Configuration";
Expand Down Expand Up @@ -420,28 +422,32 @@ export class NativeInteractionClient extends BaseInteractionClient {
response,
idTokenClaims
);
const accountEntity = AccountEntity.createAccount(
{
homeAccountId: homeAccountIdentifier,
idTokenClaims: idTokenClaims,
clientInfo: response.client_info,
nativeAccountId: response.account.id,
},
authority

const baseAccount = buildAccountToCache(
this.browserStorage,
authority,
homeAccountIdentifier,
idTokenClaims,
base64Decode,
response.client_info,
idTokenClaims.tid,
undefined,
response.account.id,
this.logger
);

// generate authenticationResult
const result = await this.generateAuthenticationResult(
response,
request,
idTokenClaims,
accountEntity,
baseAccount,
authority.canonicalAuthority,
reqTimestamp
);

// cache accounts and tokens in the appropriate storage
this.cacheAccount(accountEntity);
this.cacheAccount(baseAccount);
this.cacheNativeTokens(
response,
request,
Expand Down Expand Up @@ -580,14 +586,11 @@ export class NativeInteractionClient extends BaseInteractionClient {
idTokenClaims.tid ||
Constants.EMPTY_STRING;

const fullAccountEntity: AccountEntity = idTokenClaims
? Object.assign(new AccountEntity(), {
...accountEntity,
idTokenClaims: idTokenClaims,
})
: accountEntity;

const accountInfo = fullAccountEntity.getAccountInfo();
const accountInfo: AccountInfo | null = updateAccountTenantProfileData(
accountEntity.getAccountInfo(),
undefined, // tenantProfile optional
idTokenClaims
);

// generate PoP token as needed
const responseAccessToken = await this.generatePopAccessToken(
Expand Down
Loading
Loading