public static MsalRefreshTokenCacheItem GetAdalEntryForMsal( ICoreLogger logger, ILegacyCachePersistence legacyCachePersistence, string preferredEnvironment, IEnumerable <string> environmentAliases, string clientId, string upn, string uniqueId) { List <MsalRefreshTokenCacheItem> adalRts = GetAllAdalEntriesForMsal( logger, legacyCachePersistence, environmentAliases, clientId, upn, uniqueId); List <MsalRefreshTokenCacheItem> filteredByPrefEnv = adalRts.Where (rt => rt.Environment.Equals(preferredEnvironment, StringComparison.OrdinalIgnoreCase)).ToList(); if (filteredByPrefEnv.Any()) { return(filteredByPrefEnv.First()); } else { return(adalRts.FirstOrDefault()); } }
/// <summary> /// Algorithm to delete: /// /// DisplayableId cannot be null /// Removal is scoped by enviroment and clientId; /// /// If accountId != null then delete everything with the same clientInfo /// otherwise, delete everything with the same displayableId /// /// Notes: /// - displayableId can change rarely /// - ClientCredential Grant uses the app token cache, not the user token cache, so this algorithm does not apply /// (nor will GetAccounts / RemoveAccount work) /// /// </summary> public static void RemoveAdalUser( ICoreLogger logger, ILegacyCachePersistence legacyCachePersistence, string clientId, string displayableId, string accountOrUserId) { try { IDictionary <AdalTokenCacheKey, AdalResultWrapper> adalCache = AdalCacheOperations.Deserialize(logger, legacyCachePersistence.LoadCache()); if (!string.IsNullOrEmpty(accountOrUserId)) { RemoveEntriesWithMatchingId(clientId, accountOrUserId, adalCache); } RemoveEntriesWithMatchingName(logger, clientId, displayableId, adalCache); legacyCachePersistence.WriteCache(AdalCacheOperations.Serialize(logger, adalCache)); } catch (Exception ex) { logger.WarningPiiWithPrefix(ex, "An error occurred while deleting account in ADAL format from the cache. " + "For details please see https://aka.ms/net-cache-persistence-errors. "); } }
public static MsalRefreshTokenCacheItem GetAdalEntryForMsal( ICoreLogger logger, ILegacyCachePersistence legacyCachePersistence, IEnumerable <string> environmentAliases, string clientId, string upn, string uniqueId) { IEnumerable <MsalRefreshTokenCacheItem> adalRts = GetAllAdalEntriesForMsal( logger, legacyCachePersistence, environmentAliases, clientId, upn, uniqueId); IEnumerable <IGrouping <string, MsalRefreshTokenCacheItem> > rtGroupsByEnv = adalRts.GroupBy(rt => rt.Environment.ToLowerInvariant()); // if we have more than 1 RT per env, there is smth wrong with the ADAL cache if (rtGroupsByEnv.Any(g => g.Count() > 1)) { //Due to the fact that there is a problem with the ADAL cache that causes this exception, The ADAL cache will be removed when //this exception is triggered so that users can sign in interactivly and repopulate the cache. IDictionary <AdalTokenCacheKey, AdalResultWrapper> adalCache = AdalCacheOperations.Deserialize(logger, legacyCachePersistence.LoadCache()); adalCache.Clear(); logger.Error(MsalErrorMessage.InvalidAdalCacheMultipleRTs); legacyCachePersistence.WriteCache(AdalCacheOperations.Serialize(logger, adalCache)); return(null); } return(adalRts.FirstOrDefault()); }
private void CreateAdalCache(ILegacyCachePersistence legacyCachePersistence, string scopes) { var key = new AdalTokenCacheKey( MsalTestConstants.AuthorityHomeTenant, scopes, MsalTestConstants.ClientId, MsalTestConstants.TokenSubjectTypeUser, MsalTestConstants.UniqueId, MsalTestConstants.User.Username); var wrapper = new AdalResultWrapper() { Result = new AdalResult(null, null, DateTimeOffset.MinValue) { UserInfo = new AdalUserInfo() { UniqueId = MsalTestConstants.UniqueId, DisplayableId = MsalTestConstants.User.Username } }, RefreshToken = MsalTestConstants.ClientSecret, RawClientInfo = MsalTestConstants.RawClientId, ResourceInResponse = scopes }; IDictionary <AdalTokenCacheKey, AdalResultWrapper> dictionary = AdalCacheOperations.Deserialize(legacyCachePersistence.LoadCache()); dictionary[key] = wrapper; legacyCachePersistence.WriteCache(AdalCacheOperations.Serialize(dictionary)); }
internal TokenCache(IServiceBundle serviceBundle) { var proxy = serviceBundle?.PlatformProxy ?? PlatformProxyFactory.CreatePlatformProxy(null); _accessor = proxy.CreateTokenCacheAccessor(); _featureFlags = proxy.GetFeatureFlags(); _defaultTokenCacheBlobStorage = proxy.CreateTokenCacheBlobStorage(); if (_defaultTokenCacheBlobStorage != null) { BeforeAccess = _defaultTokenCacheBlobStorage.OnBeforeAccess; AfterAccess = _defaultTokenCacheBlobStorage.OnAfterAccess; BeforeWrite = _defaultTokenCacheBlobStorage.OnBeforeWrite; AsyncBeforeAccess = null; AsyncAfterAccess = null; AsyncBeforeWrite = null; } LegacyCachePersistence = proxy.CreateLegacyCachePersistence(); #if iOS SetIosKeychainSecurityGroup(serviceBundle.Config.IosKeychainSecurityGroup); #endif // iOS // Must happen last, this code can access things like _accessor and such above. ServiceBundle = serviceBundle; }
private void CreateAdalCache(ICoreLogger logger, ILegacyCachePersistence legacyCachePersistence, string scopes) { var key = new AdalTokenCacheKey( TestConstants.AuthorityHomeTenant, scopes, TestConstants.ClientId, TestConstants.TokenSubjectTypeUser, TestConstants.UniqueId, TestConstants.s_user.Username); var wrapper = new AdalResultWrapper() { Result = new AdalResult() { UserInfo = new AdalUserInfo() { UniqueId = TestConstants.Uid, DisplayableId = TestConstants.s_user.Username } }, RefreshToken = TestConstants.ClientSecret, RawClientInfo = TestConstants.RawClientId, ResourceInResponse = scopes }; IDictionary <AdalTokenCacheKey, AdalResultWrapper> dictionary = AdalCacheOperations.Deserialize(logger, legacyCachePersistence.LoadCache()); dictionary[key] = wrapper; legacyCachePersistence.WriteCache(AdalCacheOperations.Serialize(logger, dictionary)); }
public static MsalRefreshTokenCacheItem GetAdalEntryForMsal( ICoreLogger logger, ILegacyCachePersistence legacyCachePersistence, IEnumerable <string> environmentAliases, string clientId, string upn, string uniqueId) { IEnumerable <MsalRefreshTokenCacheItem> adalRts = GetAllAdalEntriesForMsal( logger, legacyCachePersistence, environmentAliases, clientId, upn, uniqueId); IEnumerable <IGrouping <string, MsalRefreshTokenCacheItem> > rtGroupsByEnv = adalRts.GroupBy(rt => rt.Environment.ToLowerInvariant()); // if we have more than 1 RT per env, there is smth wrong with the ADAL cache if (rtGroupsByEnv.Any(g => g.Count() > 1)) { throw new MsalClientException( MsalError.InvalidAdalCacheMultipleRTs, MsalErrorMessage.InvalidAdalCacheMultipleRTs); } return(adalRts.FirstOrDefault()); }
/// <summary> /// Returns a tuple where /// /// Item1 is a map of ClientInfo -> AdalUserInfo for those users that have ClientInfo /// Item2 is a list of AdalUserInfo for those users that do not have ClientInfo /// </summary> public static AdalUsersForMsal GetAllAdalUsersForMsal( ICoreLogger logger, ILegacyCachePersistence legacyCachePersistence, string clientId) { var userEntries = new List <AdalUserForMsalEntry>(); try { IDictionary <AdalTokenCacheKey, AdalResultWrapper> dictionary = AdalCacheOperations.Deserialize(logger, legacyCachePersistence.LoadCache()); // filter by client id dictionary.Where(p => p.Key.ClientId.Equals(clientId, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(p.Key.Authority)) .ToList() .ForEach(kvp => { userEntries.Add(new AdalUserForMsalEntry( authority: kvp.Key.Authority, clientId: clientId, clientInfo: kvp.Value.RawClientInfo, // optional, missing in ADAL v3 userInfo: kvp.Value.Result.UserInfo)); }); } catch (Exception ex) { logger.WarningPiiWithPrefix(ex, "An error occurred while reading accounts in ADAL format from the cache for MSAL. " + "For details please see https://aka.ms/net-cache-persistence-errors. "); } return(new AdalUsersForMsal(userEntries)); }
/// <summary> /// This method is so we can inject test ILegacyCachePersistence... /// </summary> internal TokenCache( IServiceBundle serviceBundle, ILegacyCachePersistence legacyCachePersistenceForTest, bool isApplicationTokenCache, ICacheSerializationProvider optionalDefaultCacheSerializer = null) : this(serviceBundle, isApplicationTokenCache, optionalDefaultCacheSerializer) { LegacyCachePersistence = legacyCachePersistenceForTest; }
public static void WriteAdalRefreshToken( ILegacyCachePersistence legacyCachePersistence, MsalRefreshTokenCacheItem rtItem, MsalIdTokenCacheItem idItem, string authority, string uniqueId, string scope) { try { if (rtItem == null) { MsalLogger.Default.Info("No refresh token available. Skipping MSAL refresh token cache write"); return; } //Using scope instead of resource because that value does not exist. STS should return it. AdalTokenCacheKey key = new AdalTokenCacheKey(authority, scope, rtItem.ClientId, TokenSubjectType.User, uniqueId, idItem.IdToken.PreferredUsername); AdalResultWrapper wrapper = new AdalResultWrapper() { Result = new AdalResult(null, null, DateTimeOffset.MinValue) { UserInfo = new AdalUserInfo() { UniqueId = uniqueId, DisplayableId = idItem.IdToken.PreferredUsername } }, RefreshToken = rtItem.Secret, RawClientInfo = rtItem.RawClientInfo, //ResourceInResponse is needed to treat RT as an MRRT. See IsMultipleResourceRefreshToken //property in AdalResultWrapper and its usage. Stronger design would be for the STS to return resource //for which the token was issued as well on v2 endpoint. ResourceInResponse = scope }; IDictionary <AdalTokenCacheKey, AdalResultWrapper> dictionary = AdalCacheOperations.Deserialize(legacyCachePersistence.LoadCache()); dictionary[key] = wrapper; legacyCachePersistence.WriteCache(AdalCacheOperations.Serialize(dictionary)); } catch (Exception ex) { if (!string.Equals(rtItem?.Environment, idItem?.Environment, StringComparison.OrdinalIgnoreCase)) { MsalLogger.Default.Error(DifferentEnvError); } if (!string.Equals(rtItem?.Environment, new Uri(authority).Host, StringComparison.OrdinalIgnoreCase)) { MsalLogger.Default.Error(DifferentAuthorityError); } MsalLogger.Default.WarningPiiWithPrefix(ex, "An error occurred while writing MSAL refresh token to the cache in ADAL format. " + "For details please see https://aka.ms/net-cache-persistence-errors. "); } }
internal static void PopulateLegacyCache(ICoreLogger logger, ILegacyCachePersistence legacyCachePersistence) { PopulateLegacyWithRtAndId( logger, legacyCachePersistence, TestConstants.ClientId, TestConstants.ProductionPrefNetworkEnvironment, "uid1", "tenantId1", "user1"); PopulateLegacyWithRtAndId( logger, legacyCachePersistence, TestConstants.ClientId, TestConstants.ProductionPrefNetworkEnvironment, "uid2", "tenantId2", "user2"); PopulateLegacyWithRtAndId( logger, legacyCachePersistence, TestConstants.ClientId, TestConstants.ProductionPrefNetworkEnvironment, null, null, "no_client_info_user3"); PopulateLegacyWithRtAndId( logger, legacyCachePersistence, TestConstants.ClientId, TestConstants.ProductionPrefNetworkEnvironment, null, null, "no_client_info_user4"); PopulateLegacyWithRtAndId( logger, legacyCachePersistence, TestConstants.ClientId, TestConstants.SovereignNetworkEnvironment, // different env "uid4", "tenantId4", "sovereign_user5"); PopulateLegacyWithRtAndId( logger, legacyCachePersistence, "other_client_id", // different client id TestConstants.SovereignNetworkEnvironment, "uid5", "tenantId5", "user6"); }
private static void PopulateLegacyWithRtAndId( ILegacyCachePersistence legacyCachePersistence, string clientId, string env, string uid, string uniqueTenantId, string username) { PopulateLegacyWithRtAndId(legacyCachePersistence, clientId, env, uid, uniqueTenantId, username, "scope1"); }
internal static void PopulateLegacyWithRtAndId( ICoreLogger logger, ILegacyCachePersistence legacyCachePersistence, string clientId, string env, string uid, string uniqueTenantId, string username) { PopulateLegacyWithRtAndId(logger, legacyCachePersistence, clientId, env, uid, uniqueTenantId, username, "scope1"); }
internal static void PopulateLegacyCache(ICoreLogger logger, ILegacyCachePersistence legacyCachePersistence, int tokenQuantity = 1) { for (int i = 1; i <= tokenQuantity; i++) { PopulateLegacyWithRtAndId( logger, legacyCachePersistence, TestConstants.ClientId, TestConstants.ProductionPrefCacheEnvironment, TestConstants.Uid, TestConstants.Utid, $"{i}{TestConstants.DisplayableId}"); } }
internal static void PopulateLegacyWithRtAndId( ICoreLogger logger, ILegacyCachePersistence legacyCachePersistence, string clientId, string env, string uid, string uniqueTenantId, string username, string scope) { string clientInfoString; string homeAccountId; if (string.IsNullOrEmpty(uid) || string.IsNullOrEmpty(uniqueTenantId)) { clientInfoString = null; homeAccountId = null; } else { clientInfoString = MockHelpers.CreateClientInfo(uid, uniqueTenantId); homeAccountId = ClientInfo.CreateFromJson(clientInfoString).ToAccountIdentifier(); } var rtItem = new MsalRefreshTokenCacheItem(env, clientId, "someRT", clientInfoString, null, homeAccountId); var idTokenCacheItem = new MsalIdTokenCacheItem( env, clientId, MockHelpers.CreateIdToken(uid, username), clientInfoString, homeAccountId, tenantId: uniqueTenantId); CacheFallbackOperations.WriteAdalRefreshToken( logger, legacyCachePersistence, rtItem, idTokenCacheItem, "https://" + env + "/common", uid, scope); }
private 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( _logger, legacyCachePersistence, rtItem, idTokenCacheItem, "https://" + env + "/common", "uid", scope); }
/// <summary> /// Returns a tuple where /// /// Item1 is a map of ClientInfo -> AdalUserInfo for those users that have ClientInfo /// Item2 is a list of AdalUserInfo for those users that do not have ClientInfo /// </summary> public static AdalUsersForMsalResult GetAllAdalUsersForMsal( ILegacyCachePersistence legacyCachePersistence, string clientId) { var clientInfoToAdalUserMap = new Dictionary <string, AdalUserInfo>(); var adalUsersWithoutClientInfo = new List <AdalUserInfo>(); try { IDictionary <AdalTokenCacheKey, AdalResultWrapper> dictionary = AdalCacheOperations.Deserialize(legacyCachePersistence.LoadCache()); // filter by client id and environment first // TODO - authority check needs to be updated for alias check List <KeyValuePair <AdalTokenCacheKey, AdalResultWrapper> > listToProcess = dictionary.Where(p => p.Key.ClientId.Equals(clientId, StringComparison.OrdinalIgnoreCase)).ToList(); foreach (KeyValuePair <AdalTokenCacheKey, AdalResultWrapper> pair in listToProcess) { if (!string.IsNullOrEmpty(pair.Value.RawClientInfo)) { clientInfoToAdalUserMap[pair.Value.RawClientInfo] = pair.Value.Result.UserInfo; } else { adalUsersWithoutClientInfo.Add(pair.Value.Result.UserInfo); } } } catch (Exception ex) { MsalLogger.Default.WarningPiiWithPrefix(ex, "An error occurred while reading accounts in ADAL format from the cache for MSAL. " + "For details please see https://aka.ms/net-cache-persistence-errors. "); return(new AdalUsersForMsalResult()); } return(new AdalUsersForMsalResult(clientInfoToAdalUserMap, adalUsersWithoutClientInfo)); }
/// <summary> /// This method is so we can inject test ILegacyCachePersistence... /// </summary> /// <param name="serviceBundle"></param> /// <param name="legacyCachePersistenceForTest"></param> internal TokenCache(IServiceBundle serviceBundle, ILegacyCachePersistence legacyCachePersistenceForTest) : this(serviceBundle) { LegacyCachePersistence = legacyCachePersistenceForTest; }
/// <summary> /// This method is so we can inject test ILegacyCachePersistence... /// </summary> internal TokenCache(IServiceBundle serviceBundle, ILegacyCachePersistence legacyCachePersistenceForTest, bool isApplicationTokenCache) : this(serviceBundle, isApplicationTokenCache) { LegacyCachePersistence = legacyCachePersistenceForTest; }
public AdalLegacyCacheManager(ILegacyCachePersistence legacyCachePersistence) { LegacyCachePersistence = legacyCachePersistence; }
public static MsalRefreshTokenCacheItem GetRefreshToken( ICoreLogger logger, ILegacyCachePersistence legacyCachePersistence, IEnumerable <string> environmentAliases, string clientId, IAccount account) { try { IDictionary <AdalTokenCacheKey, AdalResultWrapper> dictionary = AdalCacheOperations.Deserialize(logger, legacyCachePersistence.LoadCache()); IEnumerable <KeyValuePair <AdalTokenCacheKey, AdalResultWrapper> > listToProcess = dictionary.Where(p => p.Key.ClientId.Equals(clientId, StringComparison.OrdinalIgnoreCase) && environmentAliases.Contains(new Uri(p.Key.Authority).Host)); bool filtered = false; if (!string.IsNullOrEmpty(account?.Username)) { listToProcess = listToProcess.Where(p => account.Username.Equals( p.Key.DisplayableId, StringComparison.OrdinalIgnoreCase)); filtered = true; } if (!string.IsNullOrEmpty(account?.HomeAccountId?.ObjectId)) { listToProcess = listToProcess.Where(p => account.HomeAccountId.ObjectId.Equals( p.Key.UniqueId, StringComparison.OrdinalIgnoreCase)).ToList(); filtered = true; } // We should filter at leasts by one criteria to ensure we retrun adequate RT if (!filtered) { logger.Warning("Could not filter ADAL entries by either UPN or unique ID, skipping."); return(null); } return(listToProcess.Select(adalEntry => new MsalRefreshTokenCacheItem( new Uri(adalEntry.Key.Authority).Host, adalEntry.Key.ClientId, adalEntry.Value.RefreshToken, adalEntry.Value.RawClientInfo, familyId: null, homeAccountId: GetHomeAccountId(adalEntry.Value))) .FirstOrDefault()); } catch (Exception ex) { logger.WarningPiiWithPrefix(ex, "An error occurred while searching for refresh tokens in ADAL format in the cache for MSAL. " + "For details please see https://aka.ms/net-cache-persistence-errors. "); return(null); } }
internal PublicClientApplicationBuilder WithUserTokenLegacyCachePersistenceForTest(ILegacyCachePersistence legacyCachePersistence) { Config.UserTokenLegacyCachePersistenceForTest = legacyCachePersistence; return(this); }
public static List <MsalRefreshTokenCacheItem> GetAllAdalEntriesForMsal(ILegacyCachePersistence legacyCachePersistence, ISet <string> environmentAliases, string clientId, string upn, string uniqueId, string rawClientInfo) { try { IDictionary <AdalTokenCacheKey, AdalResultWrapper> dictionary = AdalCacheOperations.Deserialize(legacyCachePersistence.LoadCache()); //filter by client id and environment first //TODO - authority check needs to be updated for alias check List <KeyValuePair <AdalTokenCacheKey, AdalResultWrapper> > listToProcess = dictionary.Where(p => p.Key.ClientId.Equals(clientId, StringComparison.OrdinalIgnoreCase) && environmentAliases.Contains(new Uri(p.Key.Authority).Host)).ToList(); //if client info is provided then use it to filter if (!string.IsNullOrEmpty(rawClientInfo)) { List <KeyValuePair <AdalTokenCacheKey, AdalResultWrapper> > clientInfoEntries = listToProcess.Where(p => rawClientInfo.Equals(p.Value.RawClientInfo, StringComparison.OrdinalIgnoreCase)).ToList(); if (clientInfoEntries.Any()) { listToProcess = clientInfoEntries; } } //if upn is provided then use it to filter if (!string.IsNullOrEmpty(upn)) { List <KeyValuePair <AdalTokenCacheKey, AdalResultWrapper> > upnEntries = listToProcess.Where(p => upn.Equals(p.Key.DisplayableId, StringComparison.OrdinalIgnoreCase)).ToList(); if (upnEntries.Any()) { listToProcess = upnEntries; } } //if userId is provided then use it to filter if (!string.IsNullOrEmpty(uniqueId)) { List <KeyValuePair <AdalTokenCacheKey, AdalResultWrapper> > uniqueIdEntries = listToProcess.Where(p => uniqueId.Equals(p.Key.UniqueId, StringComparison.OrdinalIgnoreCase)).ToList(); if (uniqueIdEntries.Any()) { listToProcess = uniqueIdEntries; } } List <MsalRefreshTokenCacheItem> list = new List <MsalRefreshTokenCacheItem>(); foreach (KeyValuePair <AdalTokenCacheKey, AdalResultWrapper> pair in listToProcess) { list.Add(new MsalRefreshTokenCacheItem (new Uri(pair.Key.Authority).Host, pair.Key.ClientId, pair.Value.RefreshToken, pair.Value.RawClientInfo)); } return(list); } catch (Exception ex) { MsalLogger.Default.WarningPiiWithPrefix(ex, "An error occurred while searching for refresh tokens in ADAL format in the cache for MSAL. " + "For details please see https://aka.ms/net-cache-persistence-errors. "); return(new List <MsalRefreshTokenCacheItem>()); } }