public void TestSerializeMsalRefreshTokenCacheItemWithAdditionalFields() { var item = CreateRefreshTokenItem(); // Add an unknown field into the json var asJObject = item.ToJObject(); asJObject["unsupported_field_name"] = "this is a value"; // Ensure unknown field remains in the AdditionalFieldsJson block var item2 = MsalRefreshTokenCacheItem.FromJObject(asJObject); Assert.AreEqual("{\r\n \"unsupported_field_name\": \"this is a value\"\r\n}", item2.AdditionalFieldsJson); // Ensure additional fields make the round trip into json asJObject = item2.ToJObject(); AssertRefreshTokenHasJObjectFields( asJObject, new List <string> { "unsupported_field_name" }); }
public void GetRefreshTokenDifferentEnvironmentTest() { using (var harness = CreateTestHarness()) { ITokenCacheInternal cache = new TokenCache(harness.ServiceBundle); var rtItem = new MsalRefreshTokenCacheItem( TestConstants.SovereignNetworkEnvironment, TestConstants.ClientId, "someRT", MockHelpers.CreateClientInfo()); string rtKey = rtItem.GetKey().ToString(); cache.Accessor.SaveRefreshToken(rtItem); var authParams = harness.CreateAuthenticationRequestParameters( TestConstants.AuthorityTestTenant, TestConstants.s_scope, account: TestConstants.s_user); var rt = cache.FindRefreshTokenAsync(authParams).Result; Assert.IsNull(rt); } }
private static void PopulateLegacyWithRtAndId( ILegacyCachePersistence legacyCachePersistence, string clientId, string env, string uid, string uniqueTenantId, string username, string scope) { string clientInfoString; if (string.IsNullOrEmpty(uid) || string.IsNullOrEmpty(uniqueTenantId)) { clientInfoString = null; } else { clientInfoString = MockHelpers.CreateClientInfo(uid, uniqueTenantId); } var rtItem = new MsalRefreshTokenCacheItem(env, clientId, "someRT", clientInfoString); var idTokenCacheItem = new MsalIdTokenCacheItem( env, clientId, MockHelpers.CreateIdToken(uid, username), clientInfoString, uniqueTenantId); CacheFallbackOperations.WriteAdalRefreshToken( legacyCachePersistence, rtItem, idTokenCacheItem, "https://" + env + "/common", "uid", scope); }
public void Test_FRT_SerializeDeserialize() { var item1 = CreateRefreshTokenItem(); item1.FamilyId = null; var item2 = CreateRefreshTokenItem(); item2.FamilyId = ""; var item3 = CreateRefreshTokenItem(); item3.FamilyId = "1"; var json1 = item1.ToJsonString(); var json2 = item2.ToJsonString(); var json3 = item3.ToJsonString(); var reserialized1 = MsalRefreshTokenCacheItem.FromJsonString(json1); var reserialized2 = MsalRefreshTokenCacheItem.FromJsonString(json2); var reserialized3 = MsalRefreshTokenCacheItem.FromJsonString(json3); AssertRefreshTokenCacheItemsAreEqual(item1, reserialized1); AssertRefreshTokenCacheItemsAreEqual(item2, reserialized2); AssertRefreshTokenCacheItemsAreEqual(item3, reserialized3); }
public MsalRefreshTokenCacheItem GetRefreshToken(MsalRefreshTokenCacheKey refreshTokenKey) { return(MsalRefreshTokenCacheItem.FromJsonString(_refreshTokenSharedPreference.GetString(refreshTokenKey.ToString(), null))); }
public IReadOnlyList <MsalRefreshTokenCacheItem> GetAllRefreshTokens() { return(_refreshTokenSharedPreference.All.Values.Cast <string>().Select(x => MsalRefreshTokenCacheItem.FromJsonString(x)).ToList()); }
/// <inheritdoc /> public void SaveRefreshToken(MsalRefreshTokenCacheItem item) { _tokenCacheAccessor.SaveRefreshToken(item); }
private void AssertRefreshTokenCacheItemsAreEqual(MsalRefreshTokenCacheItem expected, MsalRefreshTokenCacheItem actual) { AssertCredentialCacheItemBaseItemsAreEqual(expected, actual); if (string.IsNullOrEmpty(expected.FamilyId)) { Assert.IsTrue(string.IsNullOrEmpty(actual.FamilyId)); } else { Assert.AreEqual(expected.FamilyId, actual.FamilyId); } }
async Task <Tuple <MsalAccessTokenCacheItem, MsalIdTokenCacheItem, Account> > ITokenCacheInternal.SaveTokenResponseAsync( AuthenticationRequestParameters requestParams, MsalTokenResponse response) { response.Log(requestParams.RequestContext.Logger, LogLevel.Verbose); MsalAccessTokenCacheItem msalAccessTokenCacheItem = null; MsalRefreshTokenCacheItem msalRefreshTokenCacheItem = null; MsalIdTokenCacheItem msalIdTokenCacheItem = null; MsalAccountCacheItem msalAccountCacheItem = null; IdToken idToken = IdToken.Parse(response.IdToken); if (idToken == null) { requestParams.RequestContext.Logger.Info("ID Token not present in response. "); } var tenantId = GetTenantId(idToken, requestParams); bool isAdfsAuthority = requestParams.AuthorityInfo.AuthorityType == AuthorityType.Adfs; string preferredUsername = GetPreferredUsernameFromIdToken(isAdfsAuthority, idToken); string username = isAdfsAuthority ? idToken?.Upn : preferredUsername; string homeAccountId = GetHomeAccountId(requestParams, response, idToken); string suggestedWebCacheKey = SuggestedWebCacheKeyFactory.GetKeyFromResponse(requestParams, homeAccountId); // Do a full instance discovery when saving tokens (if not cached), // so that the PreferredNetwork environment is up to date. var instanceDiscoveryMetadata = await ServiceBundle.InstanceDiscoveryManager .GetMetadataEntryAsync( requestParams.Authority.AuthorityInfo, requestParams.RequestContext) .ConfigureAwait(false); #region Create Cache Objects if (!string.IsNullOrEmpty(response.AccessToken)) { msalAccessTokenCacheItem = new MsalAccessTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.AppConfig.ClientId, response, tenantId, homeAccountId, requestParams.AuthenticationScheme.KeyId) { UserAssertionHash = requestParams.UserAssertion?.AssertionHash, IsAdfs = isAdfsAuthority }; } if (!string.IsNullOrEmpty(response.RefreshToken)) { msalRefreshTokenCacheItem = new MsalRefreshTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.AppConfig.ClientId, response, homeAccountId); if (!_featureFlags.IsFociEnabled) { msalRefreshTokenCacheItem.FamilyId = null; } } Dictionary <string, string> wamAccountIds = GetWamAccountIds(requestParams, response); Account account; if (idToken != null) { msalIdTokenCacheItem = new MsalIdTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.AppConfig.ClientId, response, tenantId, homeAccountId) { IsAdfs = isAdfsAuthority }; msalAccountCacheItem = new MsalAccountCacheItem( instanceDiscoveryMetadata.PreferredCache, response.ClientInfo, homeAccountId, idToken, preferredUsername, tenantId, wamAccountIds); } #endregion account = new Account( homeAccountId, username, instanceDiscoveryMetadata.PreferredNetwork, wamAccountIds); requestParams.RequestContext.Logger.Verbose("[SaveTokenResponseAsync] Entering token cache semaphore. "); await _semaphoreSlim.WaitAsync().ConfigureAwait(false); requestParams.RequestContext.Logger.Verbose("[SaveTokenResponseAsync] Entered token cache semaphore. "); try { #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = true; #pragma warning restore CS0618 // Type or member is obsolete try { ITokenCacheInternal tokenCacheInternal = this; if (tokenCacheInternal.IsTokenCacheSerialized()) { var args = new TokenCacheNotificationArgs( this, ClientId, account, hasStateChanged: true, tokenCacheInternal.IsApplicationCache, hasTokens: tokenCacheInternal.HasTokensNoLocks(), requestParams.RequestContext.UserCancellationToken, suggestedCacheKey: suggestedWebCacheKey); Stopwatch sw = Stopwatch.StartNew(); await tokenCacheInternal.OnBeforeAccessAsync(args).ConfigureAwait(false); await tokenCacheInternal.OnBeforeWriteAsync(args).ConfigureAwait(false); requestParams.RequestContext.ApiEvent.DurationInCacheInMs += sw.ElapsedMilliseconds; } if (msalAccessTokenCacheItem != null) { requestParams.RequestContext.Logger.Info("Saving AT in cache and removing overlapping ATs..."); DeleteAccessTokensWithIntersectingScopes( requestParams, instanceDiscoveryMetadata.Aliases, tenantId, msalAccessTokenCacheItem.ScopeSet, msalAccessTokenCacheItem.HomeAccountId, msalAccessTokenCacheItem.TokenType); _accessor.SaveAccessToken(msalAccessTokenCacheItem); } if (idToken != null) { requestParams.RequestContext.Logger.Info("Saving Id Token and Account in cache ..."); _accessor.SaveIdToken(msalIdTokenCacheItem); MergeWamAccountIds(msalAccountCacheItem); _accessor.SaveAccount(msalAccountCacheItem); } // if server returns the refresh token back, save it in the cache. if (msalRefreshTokenCacheItem != null) { requestParams.RequestContext.Logger.Info("Saving RT in cache..."); _accessor.SaveRefreshToken(msalRefreshTokenCacheItem); } UpdateAppMetadata(requestParams.AppConfig.ClientId, instanceDiscoveryMetadata.PreferredCache, response.FamilyId); // Do not save RT in ADAL cache for client credentials flow or B2C if (ServiceBundle.Config.LegacyCacheCompatibilityEnabled && !requestParams.IsClientCredentialRequest && requestParams.AuthorityInfo.AuthorityType != AuthorityType.B2C) { var tenatedAuthority = Authority.CreateAuthorityWithTenant(requestParams.AuthorityInfo, tenantId); var authorityWithPreferredCache = Authority.CreateAuthorityWithEnvironment( tenatedAuthority.AuthorityInfo, instanceDiscoveryMetadata.PreferredCache); CacheFallbackOperations.WriteAdalRefreshToken( Logger, LegacyCachePersistence, msalRefreshTokenCacheItem, msalIdTokenCacheItem, authorityWithPreferredCache.AuthorityInfo.CanonicalAuthority, msalIdTokenCacheItem.IdToken.ObjectId, response.Scope); } } finally { ITokenCacheInternal tokenCacheInternal = this; if (tokenCacheInternal.IsTokenCacheSerialized()) { var args = new TokenCacheNotificationArgs( this, ClientId, account, hasStateChanged: true, tokenCacheInternal.IsApplicationCache, tokenCacheInternal.HasTokensNoLocks(), requestParams.RequestContext.UserCancellationToken, suggestedCacheKey: suggestedWebCacheKey); Stopwatch sw = Stopwatch.StartNew(); await tokenCacheInternal.OnAfterAccessAsync(args).ConfigureAwait(false); requestParams.RequestContext.ApiEvent.DurationInCacheInMs += sw.ElapsedMilliseconds; } #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = false; #pragma warning restore CS0618 // Type or member is obsolete } return(Tuple.Create(msalAccessTokenCacheItem, msalIdTokenCacheItem, account)); } finally { _semaphoreSlim.Release(); requestParams.RequestContext.Logger.Verbose("[SaveTokenResponseAsync] Released token cache semaphore. "); } }
public void SaveRefreshToken(MsalRefreshTokenCacheItem item) { Save(item.GetKey(), item.ToJsonString()); }
public List <MsalRefreshTokenCacheItem> GetAllRefreshTokens(string optionalPartitionKey = null, ICoreLogger requestlogger = null) { return(_refreshTokenSharedPreference.All.Values.Cast <string>().Select(x => MsalRefreshTokenCacheItem.FromJsonString(x)).ToList()); }
public void SaveRefreshToken(MsalRefreshTokenCacheItem item) { string key = item.GetKey().ToString(); _refreshTokenCacheDictionary[key] = item; }
public IEnumerable <MsalRefreshTokenCacheItem> GetAllRefreshTokens() { return(GetPayloadAsString((int)MsalCacheKeys.iOSCredentialAttrType.RefreshToken) .Select(x => MsalRefreshTokenCacheItem.FromJsonString(x)) .ToList()); }
async Task <MsalRefreshTokenCacheItem> ITokenCacheInternal.FindRefreshTokenAsync( AuthenticationRequestParameters requestParams, string familyId) { if (requestParams.Authority == null) { return(null); } IEnumerable <MsalRefreshTokenCacheItem> allRts = Enumerable.Empty <MsalRefreshTokenCacheItem>(); await LoadFromCacheAsync( requestParams.RequestContext.CorrelationId.AsMatsCorrelationId(), CacheEvent.TokenTypes.AT, requestParams.Account, () => allRts = _accessor.GetAllRefreshTokens()) .ConfigureAwait(false); // TODO: bogavril - do we want to be silent here? var metadata = await ServiceBundle.InstanceDiscoveryManager.GetMetadataEntryTryAvoidNetworkAsync( requestParams.AuthorityInfo.CanonicalAuthority, allRts.Select(rt => rt.Environment), // if all environments are known, a network call can be avoided requestParams.RequestContext) .ConfigureAwait(false); var aliases = metadata.Aliases; IEnumerable <MsalRefreshTokenCacheKey> candidateRtKeys = aliases.Select( al => new MsalRefreshTokenCacheKey( al, requestParams.ClientId, requestParams.Account?.HomeAccountId?.Identifier, familyId)); MsalRefreshTokenCacheItem candidateRt = allRts.FirstOrDefault( rt => candidateRtKeys.Any( candidateKey => object.Equals(rt.GetKey(), candidateKey))); requestParams.RequestContext.Logger.Info("Refresh token found in the cache? - " + (candidateRt != null)); if (candidateRt != null) { return(candidateRt); } requestParams.RequestContext.Logger.Info("Checking ADAL cache for matching RT"); string upn = string.IsNullOrWhiteSpace(requestParams.LoginHint) ? requestParams.Account?.Username : requestParams.LoginHint; // ADAL legacy cache does not store FRTs if (requestParams.Account != null && string.IsNullOrEmpty(familyId)) { return(CacheFallbackOperations.GetAdalEntryForMsal( Logger, LegacyCachePersistence, metadata.PreferredCache, aliases, requestParams.ClientId, upn, requestParams.Account.HomeAccountId?.Identifier)); } return(null); }
public List <MsalRefreshTokenCacheItem> GetAllRefreshTokens(string optionalPartitionKey = null, ICoreLogger requestlogger = null) { return(GetPayloadAsString((int)MsalCacheKeys.iOSCredentialAttrType.RefreshToken) .Select(x => MsalRefreshTokenCacheItem.FromJsonString(x)) .ToList()); }
public void DeleteRefreshToken(MsalRefreshTokenCacheItem item) { Remove(item.GetKey()); }
public void SaveRefreshToken(MsalRefreshTokenCacheItem item) { _refreshTokenCacheDictionary[item.GetKey().ToString()] = item; }
public void SaveRefreshToken(MsalRefreshTokenCacheItem item) { RefreshTokenCacheDictionary[item.GetKey().ToString()] = JsonHelper.SerializeToJson(item); }
public MsalRefreshTokenCacheItem GetRefreshToken(MsalRefreshTokenCacheKey refreshTokenKey) { return(MsalRefreshTokenCacheItem.FromJsonString(GetPayload(refreshTokenKey))); }
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(); } }
public void TestGetAccounts() { var tokenCacheHelper = new TokenCacheHelper(); using (var httpManager = new MockHttpManager()) { PublicClientApplication app = PublicClientApplicationBuilder.Create(MsalTestConstants.ClientId) .WithHttpManager(httpManager) .BuildConcrete(); IEnumerable <IAccount> accounts = app.GetAccountsAsync().Result; Assert.IsNotNull(accounts); Assert.IsFalse(accounts.Any()); tokenCacheHelper.PopulateCache(app.UserTokenCacheInternal.Accessor); accounts = app.GetAccountsAsync().Result; Assert.IsNotNull(accounts); Assert.AreEqual(1, accounts.Count()); var atItem = new MsalAccessTokenCacheItem( MsalTestConstants.ProductionPrefCacheEnvironment, MsalTestConstants.ClientId, MsalTestConstants.Scope.AsSingleString(), MsalTestConstants.Utid, null, new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(3600)), new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(7200)), MockHelpers.CreateClientInfo()); atItem.Secret = atItem.GetKey().ToString(); app.UserTokenCacheInternal.Accessor.SaveAccessToken(atItem); // another cache entry for different uid. user count should be 2. MsalRefreshTokenCacheItem rtItem = new MsalRefreshTokenCacheItem( MsalTestConstants.ProductionPrefCacheEnvironment, MsalTestConstants.ClientId, "someRT", MockHelpers.CreateClientInfo("uId1", "uTId1")); app.UserTokenCacheInternal.Accessor.SaveRefreshToken(rtItem); MsalIdTokenCacheItem idTokenCacheItem = new MsalIdTokenCacheItem( MsalTestConstants.ProductionPrefCacheEnvironment, MsalTestConstants.ClientId, MockHelpers.CreateIdToken(MsalTestConstants.UniqueId, MsalTestConstants.DisplayableId), MockHelpers.CreateClientInfo("uId1", "uTId1"), "uTId1"); app.UserTokenCacheInternal.Accessor.SaveIdToken(idTokenCacheItem); MsalAccountCacheItem accountCacheItem = new MsalAccountCacheItem( MsalTestConstants.ProductionPrefCacheEnvironment, null, MockHelpers.CreateClientInfo("uId1", "uTId1"), null, null, "uTId1", null, null); app.UserTokenCacheInternal.Accessor.SaveAccount(accountCacheItem); Assert.AreEqual(2, app.UserTokenCacheInternal.Accessor.GetAllRefreshTokens().Count()); accounts = app.GetAccountsAsync().Result; Assert.IsNotNull(accounts); Assert.AreEqual(2, accounts.Count()); // scoped by env // another cache entry for different environment. user count should still be 2. Sovereign cloud user must not be returned rtItem = new MsalRefreshTokenCacheItem( MsalTestConstants.SovereignNetworkEnvironment, MsalTestConstants.ClientId, "someRT", MockHelpers.CreateClientInfo(MsalTestConstants.Uid + "more1", MsalTestConstants.Utid)); app.UserTokenCacheInternal.Accessor.SaveRefreshToken(rtItem); Assert.AreEqual(3, app.UserTokenCacheInternal.Accessor.GetAllRefreshTokens().Count()); accounts = app.GetAccountsAsync().Result; Assert.IsNotNull(accounts); Assert.AreEqual(2, accounts.Count()); } }
async Task <MsalRefreshTokenCacheItem> ITokenCacheInternal.FindRefreshTokenAsync( AuthenticationRequestParameters requestParams, string familyId) { var cacheEvent = new CacheEvent( CacheEvent.TokenCacheLookup, requestParams.RequestContext.TelemetryCorrelationId) { TokenType = CacheEvent.TokenTypes.RT }; using (ServiceBundle.TelemetryManager.CreateTelemetryHelper(cacheEvent)) { if (requestParams.Authority == null) { return(null); } var instanceDiscoveryMetadataEntry = await GetCachedOrDiscoverAuthorityMetaDataAsync( requestParams.AuthorityInfo.CanonicalAuthority, requestParams.RequestContext).ConfigureAwait(false); var environmentAliases = GetEnvironmentAliases( requestParams.AuthorityInfo.CanonicalAuthority, instanceDiscoveryMetadataEntry); var preferredEnvironmentHost = GetPreferredEnvironmentHost( requestParams.AuthorityInfo.Host, instanceDiscoveryMetadataEntry); await _semaphoreSlim.WaitAsync().ConfigureAwait(false); try { requestParams.RequestContext.Logger.Info("Looking up refresh token in the cache.."); TokenCacheNotificationArgs args = new TokenCacheNotificationArgs(this, ClientId, requestParams.Account, false); // make sure to check preferredEnvironmentHost first var allEnvAliases = new List <string>() { preferredEnvironmentHost }; allEnvAliases.AddRange(environmentAliases); var keysAcrossEnvs = allEnvAliases.Select(ea => new MsalRefreshTokenCacheKey( ea, requestParams.ClientId, requestParams.Account?.HomeAccountId?.Identifier, familyId)); await OnBeforeAccessAsync(args).ConfigureAwait(false); try { // Try to load from all env aliases, but stop at the first valid one MsalRefreshTokenCacheItem msalRefreshTokenCacheItem = keysAcrossEnvs .Select(key => _accessor.GetRefreshToken(key)) .FirstOrDefault(item => item != null); requestParams.RequestContext.Logger.Info("Refresh token found in the cache? - " + (msalRefreshTokenCacheItem != null)); if (msalRefreshTokenCacheItem != null) { return(msalRefreshTokenCacheItem); } requestParams.RequestContext.Logger.Info("Checking ADAL cache for matching RT"); string upn = string.IsNullOrWhiteSpace(requestParams.LoginHint) ? requestParams.Account?.Username : requestParams.LoginHint; // ADAL legacy cache does not store FRTs if (requestParams.Account != null && string.IsNullOrEmpty(familyId)) { return(CacheFallbackOperations.GetAdalEntryForMsal( Logger, LegacyCachePersistence, preferredEnvironmentHost, environmentAliases, requestParams.ClientId, upn, requestParams.Account.HomeAccountId?.Identifier)); } return(null); } finally { await OnAfterAccessAsync(args).ConfigureAwait(false); } } finally { _semaphoreSlim.Release(); } } }
public void DeleteRefreshToken(MsalRefreshTokenCacheItem item) { Delete(item.GetKey().ToString(), _refreshTokenSharedPreference.Edit()); }
public void SaveRefreshToken(MsalRefreshTokenCacheItem item) { string key = item.GetKey().ToString(); _refreshTokenCacheDictionary.AddOrUpdate(key, item, (k, oldValue) => item); }
public void TestMsalRefreshTokenCacheItemFromJsonStringEmpty() { var item = MsalRefreshTokenCacheItem.FromJsonString(null); Assert.IsNull(item); }
/// <summary> /// This method is not supported for the app token cache because /// there are no refresh tokens in a client credential flow. /// </summary> public void SaveRefreshToken(MsalRefreshTokenCacheItem item) { throw new NotSupportedException(); }
public void TestMsalNet2XCacheSerializationInterop() { var accessor = new InMemoryTokenCacheAccessor(Substitute.For <ICoreLogger>()); var s = new TokenCacheDictionarySerializer(accessor); string binFilePath = ResourceHelper.GetTestResourceRelativePath("cachecompat_dotnet_dictionary.bin"); byte[] bytes = File.ReadAllBytes(binFilePath); s.Deserialize(bytes, false); Assert.AreEqual(1, accessor.GetAllAccessTokens().Count()); Assert.AreEqual(1, accessor.GetAllRefreshTokens().Count()); Assert.AreEqual(1, accessor.GetAllIdTokens().Count()); Assert.AreEqual(1, accessor.GetAllAccounts().Count()); Assert.AreEqual(0, accessor.GetAllAppMetadata().Count()); var expectedAccessTokenItem = new MsalAccessTokenCacheItem("User.Read User.ReadBasic.All profile openid email") { AdditionalFieldsJson = "{\r\n \"access_token_type\": \"Bearer\"\r\n}", Environment = "login.windows.net", HomeAccountId = "13dd2c19-84cd-416a-ae7d-49573e425619.26039cce-489d-4002-8293-5b0c5134eacb", RawClientInfo = string.Empty, ClientId = "b945c513-3946-4ecd-b179-6499803a2167", TenantId = "26039cce-489d-4002-8293-5b0c5134eacb", CachedAt = "1548803419", ExpiresOnUnixTimestamp = "1548846619", ExtendedExpiresOnUnixTimestamp = "1548846619", UserAssertionHash = string.Empty, TokenType = StorageJsonValues.TokenTypeBearer }; AssertAccessTokenCacheItemsAreEqual(expectedAccessTokenItem, accessor.GetAllAccessTokens().First()); var expectedRefreshTokenItem = new MsalRefreshTokenCacheItem { Environment = "login.windows.net", HomeAccountId = "13dd2c19-84cd-416a-ae7d-49573e425619.26039cce-489d-4002-8293-5b0c5134eacb", RawClientInfo = string.Empty, ClientId = "b945c513-3946-4ecd-b179-6499803a2167" }; AssertRefreshTokenCacheItemsAreEqual(expectedRefreshTokenItem, accessor.GetAllRefreshTokens().First()); var expectedIdTokenItem = new MsalIdTokenCacheItem { Environment = "login.windows.net", HomeAccountId = "13dd2c19-84cd-416a-ae7d-49573e425619.26039cce-489d-4002-8293-5b0c5134eacb", RawClientInfo = string.Empty, ClientId = "b945c513-3946-4ecd-b179-6499803a2167", TenantId = "26039cce-489d-4002-8293-5b0c5134eacb" }; AssertIdTokenCacheItemsAreEqual(expectedIdTokenItem, accessor.GetAllIdTokens().First()); var expectedAccountItem = new MsalAccountCacheItem { Environment = "login.windows.net", HomeAccountId = "13dd2c19-84cd-416a-ae7d-49573e425619.26039cce-489d-4002-8293-5b0c5134eacb", RawClientInfo = "eyJ1aWQiOiIxM2RkMmMxOS04NGNkLTQxNmEtYWU3ZC00OTU3M2U0MjU2MTkiLCJ1dGlkIjoiMjYwMzljY2UtNDg5ZC00MDAyLTgyOTMtNWIwYzUxMzRlYWNiIn0", PreferredUsername = "******", Name = "Abhi Test", GivenName = string.Empty, FamilyName = string.Empty, LocalAccountId = "13dd2c19-84cd-416a-ae7d-49573e425619", TenantId = "26039cce-489d-4002-8293-5b0c5134eacb" }; AssertAccountCacheItemsAreEqual(expectedAccountItem, accessor.GetAllAccounts().First()); }
async Task <Tuple <MsalAccessTokenCacheItem, MsalIdTokenCacheItem> > ITokenCacheInternal.SaveTokenResponseAsync( AuthenticationRequestParameters requestParams, MsalTokenResponse response) { MsalAccessTokenCacheItem msalAccessTokenCacheItem = null; MsalRefreshTokenCacheItem msalRefreshTokenCacheItem = null; MsalIdTokenCacheItem msalIdTokenCacheItem = null; MsalAccountCacheItem msalAccountCacheItem = null; IdToken idToken = IdToken.Parse(response.IdToken); var tenantId = Authority .CreateAuthority(requestParams.TenantUpdatedCanonicalAuthority.AuthorityInfo.CanonicalAuthority) .TenantId; bool isAdfsAuthority = requestParams.AuthorityInfo.AuthorityType == AuthorityType.Adfs; string preferredUsername = GetPreferredUsernameFromIdToken(isAdfsAuthority, idToken); string username = isAdfsAuthority ? idToken?.Upn : preferredUsername; string homeAccountId = GetHomeAccountId(requestParams, response, idToken); // Do a full instance discovery when saving tokens (if not cached), // so that the PreferredNetwork environment is up to date. var instanceDiscoveryMetadata = await ServiceBundle.InstanceDiscoveryManager .GetMetadataEntryAsync( requestParams.TenantUpdatedCanonicalAuthority.AuthorityInfo.CanonicalAuthority, requestParams.RequestContext) .ConfigureAwait(false); #region Create Cache Objects if (!string.IsNullOrEmpty(response.AccessToken)) { msalAccessTokenCacheItem = new MsalAccessTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.ClientId, response, tenantId, homeAccountId, requestParams.AuthenticationScheme.KeyId) { UserAssertionHash = requestParams.UserAssertion?.AssertionHash, IsAdfs = isAdfsAuthority }; } if (!string.IsNullOrEmpty(response.RefreshToken)) { msalRefreshTokenCacheItem = new MsalRefreshTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.ClientId, response, homeAccountId); if (!_featureFlags.IsFociEnabled) { msalRefreshTokenCacheItem.FamilyId = null; } } if (idToken != null) { msalIdTokenCacheItem = new MsalIdTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.ClientId, response, tenantId, homeAccountId) { IsAdfs = isAdfsAuthority }; msalAccountCacheItem = new MsalAccountCacheItem( instanceDiscoveryMetadata.PreferredCache, response.ClientInfo, homeAccountId, idToken, preferredUsername, tenantId); } #endregion Account account = new Account( homeAccountId, username, instanceDiscoveryMetadata.PreferredCache); await _semaphoreSlim.WaitAsync().ConfigureAwait(false); try { var args = new TokenCacheNotificationArgs( this, ClientId, account, hasStateChanged: true, (this as ITokenCacheInternal).IsApplicationCache, hasTokens: (this as ITokenCacheInternal).HasTokensNoLocks(), requestParams.SuggestedWebAppCacheKey); #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = true; #pragma warning restore CS0618 // Type or member is obsolete try { await(this as ITokenCacheInternal).OnBeforeAccessAsync(args).ConfigureAwait(false); await(this as ITokenCacheInternal).OnBeforeWriteAsync(args).ConfigureAwait(false); if (msalAccessTokenCacheItem != null) { requestParams.RequestContext.Logger.Info("Saving AT in cache and removing overlapping ATs..."); DeleteAccessTokensWithIntersectingScopes( requestParams, instanceDiscoveryMetadata.Aliases, tenantId, msalAccessTokenCacheItem.ScopeSet, msalAccessTokenCacheItem.HomeAccountId, msalAccessTokenCacheItem.TokenType); _accessor.SaveAccessToken(msalAccessTokenCacheItem); } if (idToken != null) { requestParams.RequestContext.Logger.Info("Saving Id Token and Account in cache ..."); _accessor.SaveIdToken(msalIdTokenCacheItem); _accessor.SaveAccount(msalAccountCacheItem); } // if server returns the refresh token back, save it in the cache. if (msalRefreshTokenCacheItem != null) { requestParams.RequestContext.Logger.Info("Saving RT in cache..."); _accessor.SaveRefreshToken(msalRefreshTokenCacheItem); } UpdateAppMetadata(requestParams.ClientId, instanceDiscoveryMetadata.PreferredCache, response.FamilyId); // Do not save RT in ADAL cache for confidential client or B2C if (!requestParams.IsClientCredentialRequest && requestParams.AuthorityInfo.AuthorityType != AuthorityType.B2C) { var authorityWithPreferredCache = Authority.CreateAuthorityWithEnvironment( requestParams.TenantUpdatedCanonicalAuthority.AuthorityInfo, instanceDiscoveryMetadata.PreferredCache); CacheFallbackOperations.WriteAdalRefreshToken( Logger, LegacyCachePersistence, msalRefreshTokenCacheItem, msalIdTokenCacheItem, authorityWithPreferredCache.AuthorityInfo.CanonicalAuthority, msalIdTokenCacheItem.IdToken.ObjectId, response.Scope); } } finally { var args2 = new TokenCacheNotificationArgs( this, ClientId, account, hasStateChanged: true, (this as ITokenCacheInternal).IsApplicationCache, (this as ITokenCacheInternal).HasTokensNoLocks(), requestParams.SuggestedWebAppCacheKey); await(this as ITokenCacheInternal).OnAfterAccessAsync(args2).ConfigureAwait(false); #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = false; #pragma warning restore CS0618 // Type or member is obsolete } return(Tuple.Create(msalAccessTokenCacheItem, msalIdTokenCacheItem)); } finally { _semaphoreSlim.Release(); } }
async Task <Tuple <MsalAccessTokenCacheItem, MsalIdTokenCacheItem> > ITokenCacheInternal.SaveTokenResponseAsync( AuthenticationRequestParameters requestParams, MsalTokenResponse response) { var tenantId = Authority .CreateAuthority(requestParams.TenantUpdatedCanonicalAuthority.AuthorityInfo.CanonicalAuthority) .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 = GetPreferredUsernameFromIdToken(isAdfsAuthority, idToken); // Do a full instance discovery when saving tokens (if not cached), // so that the PreferredNetwork environment is up to date. var instanceDiscoveryMetadata = await ServiceBundle.InstanceDiscoveryManager .GetMetadataEntryAsync( requestParams.TenantUpdatedCanonicalAuthority.AuthorityInfo.CanonicalAuthority, requestParams.RequestContext) .ConfigureAwait(false); var msalAccessTokenCacheItem = new MsalAccessTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.ClientId, response, tenantId, subject, requestParams.AuthenticationScheme.KeyId) { UserAssertionHash = requestParams.UserAssertion?.AssertionHash, IsAdfs = isAdfsAuthority }; MsalRefreshTokenCacheItem msalRefreshTokenCacheItem = null; MsalIdTokenCacheItem msalIdTokenCacheItem = null; if (idToken != null) { msalIdTokenCacheItem = new MsalIdTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, 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, instanceDiscoveryMetadata.PreferredCache); } var args = new TokenCacheNotificationArgs(this, ClientId, account, true, (this as ITokenCacheInternal).IsApplicationCache); #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = true; #pragma warning restore CS0618 // Type or member is obsolete await(this as ITokenCacheInternal).OnBeforeAccessAsync(args).ConfigureAwait(false); try { await(this as ITokenCacheInternal).OnBeforeWriteAsync(args).ConfigureAwait(false); DeleteAccessTokensWithIntersectingScopes( requestParams, instanceDiscoveryMetadata.Aliases, tenantId, msalAccessTokenCacheItem.ScopeSet, msalAccessTokenCacheItem.HomeAccountId, msalAccessTokenCacheItem.TokenType); _accessor.SaveAccessToken(msalAccessTokenCacheItem); if (idToken != null) { _accessor.SaveIdToken(msalIdTokenCacheItem); var msalAccountCacheItem = new MsalAccountCacheItem( instanceDiscoveryMetadata.PreferredCache, response, preferredUsername, tenantId); //The ADFS direct scenario 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( instanceDiscoveryMetadata.PreferredCache, requestParams.ClientId, response, subject); if (!_featureFlags.IsFociEnabled) { msalRefreshTokenCacheItem.FamilyId = null; } requestParams.RequestContext.Logger.Info("Saving RT in cache..."); _accessor.SaveRefreshToken(msalRefreshTokenCacheItem); } UpdateAppMetadata(requestParams.ClientId, instanceDiscoveryMetadata.PreferredCache, 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)) { var authorityWithPrefferedCache = Authority.CreateAuthorityWithEnvironment( requestParams.TenantUpdatedCanonicalAuthority.AuthorityInfo, instanceDiscoveryMetadata.PreferredCache); CacheFallbackOperations.WriteAdalRefreshToken( Logger, LegacyCachePersistence, msalRefreshTokenCacheItem, msalIdTokenCacheItem, authorityWithPrefferedCache.AuthorityInfo.CanonicalAuthority, msalIdTokenCacheItem.IdToken.ObjectId, response.Scope); } } finally { await(this as ITokenCacheInternal).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(); } }
public static void AddRefreshTokenCacheItem(this ITokenCacheInternal tokenCache, MsalRefreshTokenCacheItem accessTokenItem) { lock (_lock) { tokenCache.Accessor.SaveRefreshToken(accessTokenItem); } }