async Task <Tuple <MsalAccessTokenCacheItem, MsalIdTokenCacheItem> > ITokenCacheInternal.SaveTokenResponseAsync( AuthenticationRequestParameters requestParams, MsalTokenResponse response) { var tenantId = Authority .CreateAuthority(ServiceBundle, requestParams.TenantUpdatedCanonicalAuthority) .GetTenantId(); bool isAdfsAuthority = requestParams.AuthorityInfo.AuthorityType == AuthorityType.Adfs; IdToken idToken = IdToken.Parse(response.IdToken); string subject = idToken?.Subject; if (idToken != null && string.IsNullOrEmpty(subject)) { requestParams.RequestContext.Logger.Warning("Subject not present in Id token"); } string preferredUsername; // The preferred_username value cannot be null or empty in order to comply with the ADAL/MSAL Unified cache schema. // It will be set to "preferred_username not in idtoken" if (idToken == null) { preferredUsername = NullPreferredUsernameDisplayLabel; } else if (string.IsNullOrWhiteSpace(idToken.PreferredUsername)) { if (isAdfsAuthority) { //The direct to adfs scenario does not return preferred_username in the id token so it needs to be set to the upn preferredUsername = !string.IsNullOrEmpty(idToken.Upn) ? idToken.Upn : NullPreferredUsernameDisplayLabel; } else { preferredUsername = NullPreferredUsernameDisplayLabel; } } else { preferredUsername = idToken.PreferredUsername; } var instanceDiscoveryMetadataEntry = GetCachedAuthorityMetaData(requestParams.TenantUpdatedCanonicalAuthority); var environmentAliases = GetEnvironmentAliases( requestParams.TenantUpdatedCanonicalAuthority, instanceDiscoveryMetadataEntry); var preferredEnvironmentHost = GetPreferredEnvironmentHost( requestParams.AuthorityInfo.Host, instanceDiscoveryMetadataEntry); var msalAccessTokenCacheItem = new MsalAccessTokenCacheItem(preferredEnvironmentHost, requestParams.ClientId, response, tenantId, subject) { UserAssertionHash = requestParams.UserAssertion?.AssertionHash, IsAdfs = isAdfsAuthority }; MsalRefreshTokenCacheItem msalRefreshTokenCacheItem = null; MsalIdTokenCacheItem msalIdTokenCacheItem = null; if (idToken != null) { msalIdTokenCacheItem = new MsalIdTokenCacheItem( preferredEnvironmentHost, requestParams.ClientId, response, tenantId, subject) { IsAdfs = isAdfsAuthority }; } await _semaphoreSlim.WaitAsync().ConfigureAwait(false); try { try { Account account = null; string username = isAdfsAuthority ? idToken?.Upn : preferredUsername; if (msalAccessTokenCacheItem.HomeAccountId != null) { account = new Account( msalAccessTokenCacheItem.HomeAccountId, username, preferredEnvironmentHost); } var args = new TokenCacheNotificationArgs(this, ClientId, account, true); #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = true; #pragma warning restore CS0618 // Type or member is obsolete await OnBeforeAccessAsync(args).ConfigureAwait(false); try { await OnBeforeWriteAsync(args).ConfigureAwait(false); DeleteAccessTokensWithIntersectingScopes( requestParams, environmentAliases, tenantId, msalAccessTokenCacheItem.ScopeSet, msalAccessTokenCacheItem.HomeAccountId); _accessor.SaveAccessToken(msalAccessTokenCacheItem); if (idToken != null) { _accessor.SaveIdToken(msalIdTokenCacheItem); var msalAccountCacheItem = new MsalAccountCacheItem( preferredEnvironmentHost, response, preferredUsername, tenantId); //The ADFS direct scenrio does not return client info so the home account id is acquired from the subject if (isAdfsAuthority && String.IsNullOrEmpty(msalAccountCacheItem.HomeAccountId)) { msalAccountCacheItem.HomeAccountId = idToken.Subject; } _accessor.SaveAccount(msalAccountCacheItem); } // if server returns the refresh token back, save it in the cache. if (response.RefreshToken != null) { msalRefreshTokenCacheItem = new MsalRefreshTokenCacheItem( preferredEnvironmentHost, requestParams.ClientId, response, subject); if (!_featureFlags.IsFociEnabled) { msalRefreshTokenCacheItem.FamilyId = null; } requestParams.RequestContext.Logger.Info("Saving RT in cache..."); _accessor.SaveRefreshToken(msalRefreshTokenCacheItem); } UpdateAppMetadata(requestParams.ClientId, preferredEnvironmentHost, response.FamilyId); // save RT in ADAL cache for public clients // do not save RT in ADAL cache for MSAL B2C scenarios if (!requestParams.IsClientCredentialRequest && !requestParams.AuthorityInfo.AuthorityType.Equals(AuthorityType.B2C)) { CacheFallbackOperations.WriteAdalRefreshToken( Logger, LegacyCachePersistence, msalRefreshTokenCacheItem, msalIdTokenCacheItem, Authority.CreateAuthorityUriWithHost( requestParams.TenantUpdatedCanonicalAuthority, preferredEnvironmentHost), msalIdTokenCacheItem.IdToken.ObjectId, response.Scope); } } finally { await OnAfterAccessAsync(args).ConfigureAwait(false); } return(Tuple.Create(msalAccessTokenCacheItem, msalIdTokenCacheItem)); } finally { #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = false; #pragma warning restore CS0618 // Type or member is obsolete } } finally { _semaphoreSlim.Release(); } }
async Task <Tuple <MsalAccessTokenCacheItem, MsalIdTokenCacheItem> > ITokenCacheInternal.SaveTokenResponseAsync( AuthenticationRequestParameters requestParams, MsalTokenResponse response) { var tenantId = Authority .CreateAuthority(ServiceBundle, requestParams.TenantUpdatedCanonicalAuthority) .GetTenantId(); IdToken idToken = IdToken.Parse(response.IdToken); // The preferred_username value cannot be null or empty in order to comply with the ADAL/MSAL Unified cache schema. // It will be set to "preferred_username not in idtoken" var preferredUsername = !string.IsNullOrWhiteSpace(idToken?.PreferredUsername) ? idToken.PreferredUsername : NullPreferredUsernameDisplayLabel; var instanceDiscoveryMetadataEntry = GetCachedAuthorityMetaData(requestParams.TenantUpdatedCanonicalAuthority); var environmentAliases = GetEnvironmentAliases( requestParams.TenantUpdatedCanonicalAuthority, instanceDiscoveryMetadataEntry); var preferredEnvironmentHost = GetPreferredEnvironmentHost( requestParams.AuthorityInfo.Host, instanceDiscoveryMetadataEntry); var msalAccessTokenCacheItem = new MsalAccessTokenCacheItem(preferredEnvironmentHost, requestParams.ClientId, response, tenantId) { UserAssertionHash = requestParams.UserAssertion?.AssertionHash }; MsalRefreshTokenCacheItem msalRefreshTokenCacheItem = null; MsalIdTokenCacheItem msalIdTokenCacheItem = null; if (idToken != null) { msalIdTokenCacheItem = new MsalIdTokenCacheItem( preferredEnvironmentHost, requestParams.ClientId, response, tenantId); } await _semaphoreSlim.WaitAsync().ConfigureAwait(false); try { try { var args = new TokenCacheNotificationArgs { TokenCache = new NoLockTokenCacheProxy(this), ClientId = ClientId, Account = msalAccessTokenCacheItem.HomeAccountId != null ? new Account(msalAccessTokenCacheItem.HomeAccountId, preferredUsername, preferredEnvironmentHost) : null, HasStateChanged = true }; #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = true; #pragma warning restore CS0618 // Type or member is obsolete await OnBeforeAccessAsync(args).ConfigureAwait(false); try { await OnBeforeWriteAsync(args).ConfigureAwait(false); DeleteAccessTokensWithIntersectingScopes( requestParams, environmentAliases, tenantId, msalAccessTokenCacheItem.ScopeSet, msalAccessTokenCacheItem.HomeAccountId); _accessor.SaveAccessToken(msalAccessTokenCacheItem); if (idToken != null) { _accessor.SaveIdToken(msalIdTokenCacheItem); var msalAccountCacheItem = new MsalAccountCacheItem( preferredEnvironmentHost, response, preferredUsername, tenantId); _accessor.SaveAccount(msalAccountCacheItem); } // if server returns the refresh token back, save it in the cache. if (response.RefreshToken != null) { msalRefreshTokenCacheItem = new MsalRefreshTokenCacheItem( preferredEnvironmentHost, requestParams.ClientId, response); if (!_featureFlags.IsFociEnabled) { msalRefreshTokenCacheItem.FamilyId = null; } requestParams.RequestContext.Logger.Info("Saving RT in cache..."); _accessor.SaveRefreshToken(msalRefreshTokenCacheItem); } UpdateAppMetadata(requestParams.ClientId, preferredEnvironmentHost, response.FamilyId); // save RT in ADAL cache for public clients // do not save RT in ADAL cache for MSAL B2C scenarios if (!requestParams.IsClientCredentialRequest && !requestParams.AuthorityInfo.AuthorityType.Equals(AuthorityType.B2C)) { CacheFallbackOperations.WriteAdalRefreshToken( Logger, LegacyCachePersistence, msalRefreshTokenCacheItem, msalIdTokenCacheItem, Authority.CreateAuthorityUriWithHost( requestParams.TenantUpdatedCanonicalAuthority, preferredEnvironmentHost), msalIdTokenCacheItem.IdToken.ObjectId, response.Scope); } } finally { await OnAfterAccessAsync(args).ConfigureAwait(false); } return(Tuple.Create(msalAccessTokenCacheItem, msalIdTokenCacheItem)); } finally { #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = false; #pragma warning restore CS0618 // Type or member is obsolete } } finally { _semaphoreSlim.Release(); } }