Example #1
0
        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);
        }
Example #5
0
 public MsalRefreshTokenCacheItem GetRefreshToken(MsalRefreshTokenCacheKey refreshTokenKey)
 {
     return(MsalRefreshTokenCacheItem.FromJsonString(_refreshTokenSharedPreference.GetString(refreshTokenKey.ToString(), null)));
 }
Example #6
0
 public IReadOnlyList <MsalRefreshTokenCacheItem> GetAllRefreshTokens()
 {
     return(_refreshTokenSharedPreference.All.Values.Cast <string>().Select(x => MsalRefreshTokenCacheItem.FromJsonString(x)).ToList());
 }
Example #7
0
 /// <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);
            }
        }
Example #9
0
        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());
 }
Example #11
0
 public List <MsalRefreshTokenCacheItem> GetAllRefreshTokens(string optionalPartitionKey = null, ICoreLogger requestlogger = null)
 {
     return(_refreshTokenSharedPreference.All.Values.Cast <string>().Select(x => MsalRefreshTokenCacheItem.FromJsonString(x)).ToList());
 }
Example #12
0
        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());
 }
Example #14
0
        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());
 }
Example #17
0
 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)));
 }
Example #20
0
        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();
            }
        }
Example #21
0
        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());
            }
        }
Example #22
0
        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();
                }
            }
        }
Example #23
0
 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);
        }
Example #25
0
        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());
        }
Example #28
0
        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);
     }
 }