internal void StoreToCache(AuthenticationResultEx result, string authority, string resource, string clientId, TokenSubjectType subjectType, CallState callState) { lock (cacheLock) { PlatformPlugin.Logger.Verbose(callState, "Storing token in the cache..."); string uniqueId = (result.Result.UserInfo != null) ? result.Result.UserInfo.UniqueId : null; string displayableId = (result.Result.UserInfo != null) ? result.Result.UserInfo.DisplayableId : null; this.OnBeforeWrite(new TokenCacheNotificationArgs { Resource = resource, ClientId = clientId, UniqueId = uniqueId, DisplayableId = displayableId }); TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, resource, clientId, subjectType, result.Result.UserInfo); this.tokenCacheDictionary[tokenCacheKey] = result; PlatformPlugin.Logger.Verbose(callState, "An item was stored in the cache"); this.UpdateCachedMrrtRefreshTokens(result, clientId, subjectType); this.HasStateChanged = true; } }
internal bool Match(TokenCacheKey key) { return(key.Authority == this.Authority && key.ResourceEquals(this.Resource) && key.ClientIdEquals(this.ClientId) && key.TokenSubjectType == this.TokenSubjectType && key.UniqueId == this.UniqueId && key.DisplayableIdEquals(this.DisplayableId)); }
public static TokenCacheKey DecodeCacheKey(string cacheKey) { var elements = new TokenCacheKey(); IDictionary<TokenCacheKeyElement, string> elementDictionary = Decode(cacheKey); elements.Authority = elementDictionary.ContainsKey(TokenCacheKeyElement.Authority) ? elementDictionary[TokenCacheKeyElement.Authority] : null; elements.ClientId = elementDictionary.ContainsKey(TokenCacheKeyElement.ClientId) ? elementDictionary[TokenCacheKeyElement.ClientId] : null; elements.FamilyName = elementDictionary.ContainsKey(TokenCacheKeyElement.FamilyName) ? elementDictionary[TokenCacheKeyElement.FamilyName] : null; elements.GivenName = elementDictionary.ContainsKey(TokenCacheKeyElement.GivenName) ? elementDictionary[TokenCacheKeyElement.GivenName] : null; elements.IdentityProviderName = elementDictionary.ContainsKey(TokenCacheKeyElement.IdentityProviderName) ? elementDictionary[TokenCacheKeyElement.IdentityProviderName] : null; elements.Resource = elementDictionary.ContainsKey(TokenCacheKeyElement.Resource) ? elementDictionary[TokenCacheKeyElement.Resource] : null; elements.TenantId = elementDictionary.ContainsKey(TokenCacheKeyElement.TenantId) ? elementDictionary[TokenCacheKeyElement.TenantId] : null; elements.UserId = elementDictionary.ContainsKey(TokenCacheKeyElement.UserId) ? elementDictionary[TokenCacheKeyElement.UserId] : null; if (elementDictionary.ContainsKey(TokenCacheKeyElement.ExpiresOn)) { elements.ExpiresOn = DateTimeOffset.Parse(elementDictionary[TokenCacheKeyElement.ExpiresOn]); } if (elementDictionary.ContainsKey(TokenCacheKeyElement.IsUserIdDisplayable)) { elements.IsUserIdDisplayable = bool.Parse(elementDictionary[TokenCacheKeyElement.IsUserIdDisplayable]); } if (elementDictionary.ContainsKey(TokenCacheKeyElement.IsMultipleResourceRefreshToken)) { elements.IsMultipleResourceRefreshToken = bool.Parse(elementDictionary[TokenCacheKeyElement.IsMultipleResourceRefreshToken]); } return elements; }
public void DeleteItem(TokenCacheItem item) #endif { if (item == null) { throw new ArgumentNullException("item"); } TokenCacheNotificationArgs args = new TokenCacheNotificationArgs { TokenCache = this, Resource = item.Resource, ClientId = item.ClientId, UniqueId = item.UniqueId, DisplayableId = item.DisplayableId }; this.OnBeforeAccess(args); this.OnBeforeWrite(args); TokenCacheKey toRemoveKey = this.tokenCacheDictionary.Keys.FirstOrDefault(item.Match); if (toRemoveKey != null) { this.tokenCacheDictionary.Remove(toRemoveKey); } this.HasStateChanged = true; this.OnAfterAccess(args); }
public async Task AcquireTokenSilentServiceErrorTestAsync() { Sts sts = new AadSts(); TokenCache cache = new TokenCache(); TokenCacheKey key = new TokenCacheKey(sts.Authority, sts.ValidResource, sts.ValidClientId, TokenSubjectType.User, "unique_id", "*****@*****.**"); cache.tokenCacheDictionary[key] = new AuthenticationResult("Bearer", "some-access-token", "invalid-refresh-token", DateTimeOffset.UtcNow); AuthenticationContext context = new AuthenticationContext(sts.Authority, sts.ValidateAuthority, cache); try { await context.AcquireTokenSilentAsync(sts.ValidResource, sts.ValidClientId, new UserIdentifier("unique_id", UserIdentifierType.UniqueId)); Verify.Fail("AdalSilentTokenAcquisitionException was expected"); } catch (AdalSilentTokenAcquisitionException ex) { Verify.AreEqual(AdalError.FailedToAcquireTokenSilently, ex.ErrorCode); Verify.AreEqual(AdalErrorMessage.FailedToRefreshToken, ex.Message); Verify.IsNotNull(ex.InnerException); Verify.IsTrue(ex.InnerException is AdalException); Verify.AreEqual(((AdalException)ex.InnerException).ErrorCode, "invalid_grant"); } catch { Verify.Fail("AdalSilentTokenAcquisitionException was expected"); } }
internal AuthenticationResult LoadFromCache(string authority, string resource, string clientId, TokenSubjectType subjectType, string uniqueId, string displayableId, CallState callState) { AuthenticationResult result = null; KeyValuePair <TokenCacheKey, AuthenticationResult>?kvp = this.LoadSingleItemFromCache(authority, resource, clientId, subjectType, uniqueId, displayableId); if (kvp.HasValue) { TokenCacheKey cacheKey = kvp.Value.Key; result = kvp.Value.Value; bool tokenMarginallyExpired = (result.ExpiresOn <= DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes)); if (tokenMarginallyExpired || !cacheKey.ResourceEquals(resource)) { result.AccessToken = null; } if (result.AccessToken == null && result.RefreshToken == null) { this.tokenCacheDictionary.Remove(cacheKey); this.HasStateChanged = true; result = null; } if (result != null) { Logger.Verbose(callState, "A matching token was found in the cache"); } } return(result); }
public static string EncodeCacheKey(TokenCacheKey cacheKey) { var keyElements = new SortedDictionary<TokenCacheKeyElement, string>(); keyElements[TokenCacheKeyElement.Authority] = cacheKey.Authority; if (!String.IsNullOrEmpty(cacheKey.Resource)) { keyElements[TokenCacheKeyElement.Resource] = cacheKey.Resource; } if (!String.IsNullOrEmpty(cacheKey.ClientId)) { keyElements[TokenCacheKeyElement.ClientId] = cacheKey.ClientId; } if (null != cacheKey.ExpiresOn) { keyElements[TokenCacheKeyElement.ExpiresOn] = cacheKey.ExpiresOn.ToString(); } if (!String.IsNullOrEmpty(cacheKey.FamilyName)) { keyElements[TokenCacheKeyElement.FamilyName] = cacheKey.FamilyName; } if (!String.IsNullOrEmpty(cacheKey.GivenName)) { keyElements[TokenCacheKeyElement.GivenName] = cacheKey.GivenName; } if (!String.IsNullOrEmpty(cacheKey.IdentityProviderName)) { keyElements[TokenCacheKeyElement.IdentityProviderName] = cacheKey.IdentityProviderName; } if (cacheKey.IsMultipleResourceRefreshToken) { keyElements[TokenCacheKeyElement.IsMultipleResourceRefreshToken] = cacheKey.IsMultipleResourceRefreshToken.ToString(); } if (cacheKey.IsUserIdDisplayable) { keyElements[TokenCacheKeyElement.IsUserIdDisplayable] = cacheKey.IsUserIdDisplayable.ToString(); } if (!String.IsNullOrEmpty(cacheKey.TenantId)) { keyElements[TokenCacheKeyElement.TenantId] = cacheKey.TenantId; } if (!String.IsNullOrEmpty(cacheKey.UserId)) { keyElements[TokenCacheKeyElement.UserId] = cacheKey.UserId; } return CreateFromKeyElements(keyElements); }
/// <summary> /// Determines whether the specified TokenCacheKey is equal to the current object. /// </summary> /// <returns> /// true if the specified TokenCacheKey is equal to the current object; otherwise, false. /// </returns> /// <param name="other">The TokenCacheKey to compare with the current object. </param><filterpriority>2</filterpriority> public bool Equals(TokenCacheKey other) { return(ReferenceEquals(this, other) || (other != null && (other.Authority == this.Authority) && this.ResourceEquals(other.Resource) && this.ClientIdEquals(other.ClientId) && (other.UniqueId == this.UniqueId) && this.DisplayableIdEquals(other.DisplayableId) && (other.TokenSubjectType == this.TokenSubjectType))); }
internal AuthenticationResult LoadFromCache(string authority, string resource, string clientId, TokenSubjectType subjectType, string uniqueId, string displayableId, CallState callState) { Logger.Verbose(callState, "Looking up cache for a token..."); AuthenticationResult result = null; KeyValuePair <TokenCacheKey, AuthenticationResult>?kvp = this.LoadSingleItemFromCache(authority, resource, clientId, subjectType, uniqueId, displayableId, callState); if (kvp.HasValue) { TokenCacheKey cacheKey = kvp.Value.Key; result = kvp.Value.Value; bool tokenNearExpiry = (result.ExpiresOn <= DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes)); if (tokenNearExpiry) { result.AccessToken = null; Logger.Verbose(callState, "An expired or near expiry token was found in the cache"); } else if (!cacheKey.ResourceEquals(resource)) { Logger.Verbose(callState, string.Format("Multi resource refresh token for resource '{0}' will be used to acquire token for '{1}'", cacheKey.Resource, resource)); var newResult = new AuthenticationResult(null, null, result.RefreshToken, DateTimeOffset.MinValue); newResult.UpdateTenantAndUserInfo(result.TenantId, result.IdToken, result.UserInfo); result = newResult; } else { Logger.Verbose(callState, string.Format("{0} minutes left until token in cache expires", (result.ExpiresOn - DateTime.UtcNow).TotalMinutes)); } if (result.AccessToken == null && result.RefreshToken == null) { this.tokenCacheDictionary.Remove(cacheKey); Logger.Information(callState, "An old item was removed from the cache"); this.HasStateChanged = true; result = null; } if (result != null) { Logger.Information(callState, "A matching item (access token or refresh token or both) was found in the cache"); } } else { Logger.Information(callState, "No matching token was found in the cache"); } return(result); }
/// <summary> /// Deserializes state of the cache. The state should be the blob received earlier by calling the method Serialize. /// </summary> /// <param name="state">State of the cache as a blob</param> public void Deserialize(byte[] state) { lock (cacheLock) { if (state == null) { this.tokenCacheDictionary.Clear(); return; } using (Stream stream = new MemoryStream()) { BinaryWriter writer = new BinaryWriter(stream); writer.Write(state); writer.Flush(); stream.Position = 0; BinaryReader reader = new BinaryReader(stream); int schemaVersion = reader.ReadInt32(); if (schemaVersion != SchemaVersion) { CallState.Default.Logger.Warning(null, "The version of the persistent state of the cache does not match the current schema, so skipping deserialization."); return; } this.tokenCacheDictionary.Clear(); int count = reader.ReadInt32(); for (int n = 0; n < count; n++) { string keyString = reader.ReadString(); string[] kvpElements = keyString.Split(new[] { Delimiter }, StringSplitOptions.None); AuthenticationResultEx resultEx = AuthenticationResultEx.Deserialize(reader.ReadString()); TokenCacheKey key = new TokenCacheKey(kvpElements[0], kvpElements[1], kvpElements[2], (TokenSubjectType)int.Parse(kvpElements[3], CultureInfo.CurrentCulture), resultEx.Result.UserInfo); this.tokenCacheDictionary.Add(key, resultEx); } CallState.Default.Logger.Information(null, string.Format(CultureInfo.CurrentCulture, "Deserialized {0} items to token cache.", count)); } } }
/// <summary> /// Default constructor. /// </summary> internal TokenCacheItem(TokenCacheKey key, AuthenticationResult result) { this.Authority = key.Authority; this.Resource = key.Resource; this.ClientId = key.ClientId; this.TokenSubjectType = key.TokenSubjectType; this.UniqueId = key.UniqueId; this.DisplayableId = key.DisplayableId; this.TenantId = result.TenantId; this.ExpiresOn = result.ExpiresOn; this.AccessToken = result.AccessToken; this.IdToken = result.IdToken; if (result.UserInfo != null) { this.FamilyName = result.UserInfo.FamilyName; this.GivenName = result.UserInfo.GivenName; this.IdentityProvider = result.UserInfo.IdentityProvider; } }
internal void StoreToCache(AuthenticationResult result, string authority, string resource, string clientId, TokenSubjectType subjectType) { string uniqueId = (result.UserInfo != null) ? result.UserInfo.UniqueId : null; string displayableId = (result.UserInfo != null) ? result.UserInfo.DisplayableId : null; this.OnBeforeWrite(new TokenCacheNotificationArgs { Resource = resource, ClientId = clientId, UniqueId = uniqueId, DisplayableId = displayableId }); TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, resource, clientId, subjectType, result.UserInfo); this.tokenCacheDictionary[tokenCacheKey] = result; this.UpdateCachedMrrtRefreshTokens(result, authority, clientId, subjectType); this.HasStateChanged = true; }
/// <summary> /// Default constructor. /// </summary> internal TokenCacheItem(TokenCacheKey key, AuthenticationResult result) { this.Authority = key.Authority; this.Resource = key.Resource; this.ClientId = key.ClientId; this.TokenSubjectType = key.TokenSubjectType; this.UniqueId = key.UniqueId; this.DisplayableId = key.DisplayableId; this.TenantId = result.TenantId; this.ExpiresOn = result.ExpiresOn; this.AccessToken = result.AccessToken; this.IdToken = result.IdToken; if (result.UserInfo != null) { this.FamilyName = result.UserInfo.FamilyName; this.GivenName = result.UserInfo.GivenName; this.IdentityProvider = result.UserInfo.IdentityProvider; } }
/// <summary> /// Deserializes state of the cache. The state should be the blob received earlier by calling the method Serialize. /// </summary> /// <param name="state">State of the cache as a blob</param> public void Deserialize([ReadOnlyArray] byte[] state) { if (state == null) { this.tokenCacheDictionary.Clear(); return; } using (Stream stream = new MemoryStream()) { BinaryWriter writer = new BinaryWriter(stream); writer.Write(state); writer.Flush(); stream.Position = 0; BinaryReader reader = new BinaryReader(stream); int schemaVersion = reader.ReadInt32(); if (schemaVersion != SchemaVersion) { // The version of the serialized cache does not match the current schema return; } this.tokenCacheDictionary.Clear(); int count = reader.ReadInt32(); for (int n = 0; n < count; n++) { string keyString = reader.ReadString(); string[] kvpElements = keyString.Split(new[] { Delimiter }, StringSplitOptions.None); AuthenticationResult result = AuthenticationResult.Deserialize(reader.ReadString()); TokenCacheKey key = new TokenCacheKey(kvpElements[0], kvpElements[1], kvpElements[2], (TokenSubjectType)int.Parse(kvpElements[3]), result.UserInfo); this.tokenCacheDictionary.Add(key, result); } } }
public void DeleteItem(TokenCacheItem item) #endif { lock (cacheLock) { if (item == null) { throw new ArgumentNullException("item"); } TokenCacheNotificationArgs args = new TokenCacheNotificationArgs { TokenCache = this, Resource = item.Resource, ClientId = item.ClientId, UniqueId = item.UniqueId, DisplayableId = item.DisplayableId }; this.OnBeforeAccess(args); this.OnBeforeWrite(args); TokenCacheKey toRemoveKey = this.tokenCacheDictionary.Keys.FirstOrDefault(item.Match); if (toRemoveKey != null) { this.tokenCacheDictionary.Remove(toRemoveKey); Logger.Information(null, "One item removed successfully"); } else { Logger.Information(null, "Item not Present in the Cache"); } this.HasStateChanged = true; this.OnAfterAccess(args); } }
private static bool RemoveFromDictionary(TokenCache tokenCache, TokenCacheKey key) { bool result; tokenCache.OnBeforeAccess(null); tokenCache.OnBeforeWrite(null); result = tokenCache.tokenCacheDictionary.Remove(key); tokenCache.HasStateChanged = true; tokenCache.OnAfterAccess(null); return result; }
private static void AddToDictionary(TokenCache tokenCache, TokenCacheKey key, AuthenticationResult value) { tokenCache.OnBeforeAccess(null); tokenCache.OnBeforeWrite(null); tokenCache.tokenCacheDictionary.Add(key, value); tokenCache.HasStateChanged = true; tokenCache.OnAfterAccess(null); }
private static bool AreEqual(TokenCacheItem item, TokenCacheKey key) { return item.Match(key); }
private static void VerifyCacheItems(TokenCache cache, int expectedCount, TokenCacheKey firstKey, TokenCacheKey secondKey) { var items = cache.ReadItems().ToList(); Verify.AreEqual(expectedCount, items.Count); if (firstKey != null) { Verify.IsTrue(AreEqual(items[0], firstKey) || AreEqual(items[0], secondKey)); } if (secondKey != null) { Verify.IsTrue(AreEqual(items[1], firstKey) || AreEqual(items[1], secondKey)); } }
private static void VerifyCacheItems(TokenCache cache, int expectedCount, TokenCacheKey firstKey) { VerifyCacheItems(cache, expectedCount, firstKey, null); }
internal void StoreToCache(AuthenticationResultEx result, string authority, string[] scope, string clientId, TokenSubjectType subjectType, CallState callState) { PlatformPlugin.Logger.Verbose(callState, "Storing token in the cache..."); if (ADALScopeHelper.IsNullOrEmpty(scope) || ADALScopeHelper.CreateSetFromArray(scope).Contains("openid")) { scope = new[] {clientId}; } string uniqueId = (result.Result.UserInfo != null) ? result.Result.UserInfo.UniqueId : null; string displayableId = (result.Result.UserInfo != null) ? result.Result.UserInfo.DisplayableId : null; this.OnBeforeWrite(new TokenCacheNotificationArgs { Scope = scope, ClientId = clientId, UniqueId = uniqueId, DisplayableId = displayableId }); TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, scope, clientId, subjectType, result.Result.UserInfo); // First identify all potential tokens. List<KeyValuePair<TokenCacheKey, AuthenticationResultEx>> items = this.QueryCache(authority, clientId, subjectType, uniqueId, displayableId); List<KeyValuePair<TokenCacheKey, AuthenticationResultEx>> itemsToRemove = items.Where(p => p.Key.ScopeIntersects(scope)).ToList(); if (!itemsToRemove.Any()) { this.tokenCacheDictionary[tokenCacheKey] = result; PlatformPlugin.Logger.Verbose(callState, "An item was stored in the cache"); } else { //remove all intersections foreach (var itemToRemove in itemsToRemove) { this.tokenCacheDictionary.Remove(itemToRemove); } this.tokenCacheDictionary[tokenCacheKey] = result; PlatformPlugin.Logger.Verbose(callState, "An item was updated in the cache"); } this.UpdateCachedMrrtRefreshTokens(result, authority, clientId, subjectType); this.HasStateChanged = true; }
internal AuthenticationResultEx LoadFromCache(CacheQueryData cacheQueryData, CallState callState) { lock (cacheLock) { PlatformPlugin.Logger.Verbose(callState, "Looking up cache for a token..."); AuthenticationResultEx resultEx = null; KeyValuePair <TokenCacheKey, AuthenticationResultEx>?kvp = this.LoadSingleItemFromCache(cacheQueryData, callState); if (kvp.HasValue) { TokenCacheKey cacheKey = kvp.Value.Key; resultEx = kvp.Value.Value.Clone(); bool tokenNearExpiry = (resultEx.Result.ExpiresOn <= DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes)); bool tokenExtendedLifeTimeExpired = (resultEx.Result.ExtendedExpiresOn <= DateTime.UtcNow); //check for cross-tenant authority if (!cacheKey.Authority.Equals(cacheQueryData.Authority)) { // this is a cross-tenant result. use RT only resultEx.Result.AccessToken = null; PlatformPlugin.Logger.Information(callState, "Cross Tenant refresh token was found in the cache"); } else if (tokenNearExpiry && !cacheQueryData.ExtendedLifeTimeEnabled) { resultEx.Result.AccessToken = null; PlatformPlugin.Logger.Information(callState, "An expired or near expiry token was found in the cache"); } else if (!cacheKey.ResourceEquals(cacheQueryData.Resource)) { PlatformPlugin.Logger.Information(callState, string.Format(CultureInfo.CurrentCulture, "Multi resource refresh token for resource '{0}' will be used to acquire token for '{1}'", cacheKey.Resource, cacheQueryData.Resource)); var newResultEx = new AuthenticationResultEx { Result = new AuthenticationResult(null, null, DateTimeOffset.MinValue), RefreshToken = resultEx.RefreshToken, ResourceInResponse = resultEx.ResourceInResponse }; newResultEx.Result.UpdateTenantAndUserInfo(resultEx.Result.TenantId, resultEx.Result.IdToken, resultEx.Result.UserInfo); resultEx = newResultEx; } else if (!tokenExtendedLifeTimeExpired && cacheQueryData.ExtendedLifeTimeEnabled && tokenNearExpiry) { resultEx.Result.ExtendedLifeTimeToken = true; resultEx.Result.ExpiresOn = resultEx.Result.ExtendedExpiresOn; PlatformPlugin.Logger.Information(callState, "The extendedLifeTime is enabled and a stale AT with extendedLifeTimeEnabled is returned."); } else if (tokenExtendedLifeTimeExpired) { resultEx.Result.AccessToken = null; PlatformPlugin.Logger.Information(callState, "The AT has expired its ExtendedLifeTime"); } else { PlatformPlugin.Logger.Information(callState, string.Format(CultureInfo.CurrentCulture, "{0} minutes left until token in cache expires", (resultEx.Result.ExpiresOn - DateTime.UtcNow).TotalMinutes)); } if (resultEx.Result.AccessToken == null && resultEx.RefreshToken == null) { this.tokenCacheDictionary.Remove(cacheKey); PlatformPlugin.Logger.Information(callState, "An old item was removed from the cache"); this.HasStateChanged = true; resultEx = null; } if (resultEx != null) { PlatformPlugin.Logger.Information(callState, "A matching item (access token or refresh token or both) was found in the cache"); } } else { PlatformPlugin.Logger.Information(callState, "No matching token was found in the cache"); } return(resultEx); } }
private static bool RemoveFromDictionary(TokenCache tokenCache, TokenCacheKey key) { tokenCache.OnBeforeAccess(new TokenCacheNotificationArgs { TokenCache = tokenCache }); tokenCache.OnBeforeWrite(new TokenCacheNotificationArgs { TokenCache = tokenCache }); bool result = tokenCache.tokenCacheDictionary.Remove(key); tokenCache.HasStateChanged = true; tokenCache.OnAfterAccess(new TokenCacheNotificationArgs { TokenCache = tokenCache }); return result; }
public static void DefaultTokenCacheTest() { AuthenticationContext context = new AuthenticationContext("https://login.windows.net/dummy", false); var cache = context.TokenCache; cache.Clear(); Log.Comment("====== Verifying that cache is empty..."); VerifyCacheItemCount(cache, 0); const string DisplayableId = "*****@*****.**"; Log.Comment("====== Creating a set of keys and values for the test..."); TokenCacheKey key = new TokenCacheKey("https://localhost/MockSts", ValidResource, ValidClientId, TokenSubjectType.User, null, DisplayableId); var value = CreateCacheValue(key.UniqueId, key.DisplayableId); Log.Comment(string.Format("Cache Key (with User): {0}", key)); Log.Comment(string.Format("Cache Value 1: {0}", value)); TokenCacheKey key2 = new TokenCacheKey("https://localhost/MockSts", InvalidResource, ValidClientId, TokenSubjectType.User, null, DisplayableId); var value2 = CreateCacheValue(null, DisplayableId); Log.Comment(string.Format("Cache Key (with User): {0}", key)); Log.Comment(string.Format("Cache Value 2: {0}", value2)); TokenCacheKey userlessKey = new TokenCacheKey("https://localhost/MockSts", ValidResource, ValidClientId, TokenSubjectType.User, null, null); var userlessValue = CreateCacheValue(null, null); Log.Comment(string.Format("Cache Key (withoutUser): {0}", userlessKey)); Log.Comment(string.Format("Cache Value 3: {0}", userlessValue)); TokenCacheKey incorrectUserKey = new TokenCacheKey("https://localhost/MockSts", InvalidResource, ValidClientId, TokenSubjectType.User, null, "*****@*****.**"); Log.Comment("====== Verifying that cache stores the first key/value pair..."); AddToDictionary(cache, key, value); VerifyCacheItems(cache, 1, key); Log.Comment("====== Verifying that the only existing value (with user) is retrieved when requested with user and NOT without..."); Log.Comment("Retrieving with user..."); var valueInCache = cache.tokenCacheDictionary[key]; VerifyAuthenticationResultsAreEqual(value, valueInCache); Log.Comment("Retrieving without user..."); cache.tokenCacheDictionary.TryGetValue(userlessKey, out valueInCache); Verify.IsNull(valueInCache); Log.Comment("====== Verifying that two entries can exist at the same time, one with user and one without..."); AddToDictionary(cache, userlessKey, userlessValue); VerifyCacheItems(cache, 2, key, userlessKey); Log.Comment("====== Verifying that correct values are retrieved when requested with and without user (when two entries exist)..."); Log.Comment("Retrieving without user..."); valueInCache = cache.tokenCacheDictionary[userlessKey]; VerifyAuthenticationResultsAreEqual(userlessValue, valueInCache); Log.Comment("Retrieving with user..."); valueInCache = cache.tokenCacheDictionary[key]; VerifyAuthenticationResultsAreEqual(value, valueInCache); Log.Comment("====== Verifying that correct entry is deleted when the key with user is passed..."); RemoveFromDictionary(cache, key); VerifyCacheItems(cache, 1, userlessKey); Log.Comment("====== Verifying that correct entry is deleted when the key without user is passed..."); AddToDictionary(cache, key, value); RemoveFromDictionary(cache, userlessKey); VerifyCacheItems(cache, 1, key); Log.Comment("====== Verifying that correct entry is retrieve and later deleted when the key with user is passed, even if entries are in reverse order..."); cache.Clear(); Log.Comment("Storing without user first and then with user..."); AddToDictionary(cache, userlessKey, userlessValue); AddToDictionary(cache, key2, value2); valueInCache = cache.tokenCacheDictionary[key2]; VerifyAuthenticationResultsAreEqual(value2, valueInCache); RemoveFromDictionary(cache, key2); VerifyCacheItems(cache, 1, userlessKey); Log.Comment("====== Verifying that the userless entry is retrieved ONLY when requested without user..."); cache.Clear(); AddToDictionary(cache, userlessKey, value); Log.Comment("Retrieving with user..."); cache.tokenCacheDictionary.TryGetValue(key, out valueInCache); Verify.IsNull(valueInCache); Log.Comment("Retrieving without user..."); valueInCache = cache.tokenCacheDictionary[userlessKey]; VerifyAuthenticationResultsAreEqual(value, valueInCache); Log.Comment("====== Verifying that entry cannot be retrieved with incorrect key..."); cache.Clear(); AddToDictionary(cache, key, value); Log.Comment("Retrieving with incorrect key..."); cache.tokenCacheDictionary.TryGetValue(key2, out valueInCache); Verify.IsNull(valueInCache); Log.Comment("Retrieving with incorrect user..."); cache.tokenCacheDictionary.TryGetValue(incorrectUserKey, out valueInCache); Verify.IsNull(valueInCache); Log.Comment("Retrieving with correct user..."); valueInCache = cache.tokenCacheDictionary[key]; VerifyAuthenticationResultsAreEqual(value, valueInCache); Log.Comment("====== Verifying that removing items from an empty cache will not throw..."); Log.Comment("Clearing cache..."); cache.Clear(); Log.Comment("Storing an entry..."); AddToDictionary(cache, key, value); VerifyCacheItemCount(cache, 1); Log.Comment("Remvoing the only entry..."); RemoveFromDictionary(cache, key); VerifyCacheItemCount(cache, 0); Log.Comment("Trying to remove from an empty cache..."); RemoveFromDictionary(cache, key); VerifyCacheItemCount(cache, 0); }
internal static void TokenCacheOperationsTest() { var tokenCache = new TokenCache(); var cacheDictionary = tokenCache.tokenCacheDictionary; tokenCache.Clear(); TokenCacheKey key = new TokenCacheKey("https://localhost/MockSts", "resource1", "client1", TokenSubjectType.User, null, "user1"); TokenCacheKey key2 = new TokenCacheKey("https://localhost/MockSts", "resource1", "client1", TokenSubjectType.User, null, "user2"); TokenCacheKey key3 = new TokenCacheKey("https://localhost/MockSts", "resource1", "client1", TokenSubjectType.UserPlusClient, null, "user1"); Verify.AreNotEqual(key, key3); var value = CreateCacheValue(null, "user1"); AuthenticationResult value2; do { value2 = CreateCacheValue(null, "user2"); } while (value2 == value); Verify.AreEqual(0, cacheDictionary.Count); AddToDictionary(tokenCache, key, value); Verify.AreEqual(1, cacheDictionary.Count); var valueInCache = cacheDictionary[key]; VerifyAuthenticationResultsAreEqual(valueInCache, value); VerifyAuthenticationResultsAreNotEqual(valueInCache, value2); cacheDictionary[key] = value2; Verify.AreEqual(1, cacheDictionary.Count); valueInCache = cacheDictionary[key]; VerifyAuthenticationResultsAreEqual(valueInCache, value2); VerifyAuthenticationResultsAreNotEqual(valueInCache, value); try { AddToDictionary(tokenCache, key, value); Verify.Fail("Exception expected due to duplicate key"); } catch (ArgumentException) { // Expected } Verify.IsTrue(RemoveFromDictionary(tokenCache, key)); Verify.IsFalse(RemoveFromDictionary(tokenCache, key)); Verify.AreEqual(0, cacheDictionary.Count); AddToDictionary(tokenCache, key, value); AddToDictionary(tokenCache, key2, value2); Verify.AreEqual(2, cacheDictionary.Count); Verify.AreEqual(cacheDictionary[key], value); Verify.AreEqual(cacheDictionary[key2], value2); try { AddToDictionary(tokenCache, null, value); Verify.Fail("Exception expected due to duplicate key"); } catch (ArgumentNullException) { // Expected } try { cacheDictionary[null] = value; Verify.Fail("Exception expected due to duplicate key"); } catch (ArgumentNullException) { // Expected } Verify.IsFalse(cacheDictionary.IsReadOnly); var keys = cacheDictionary.Keys.ToList(); var values = cacheDictionary.Values.ToList(); Verify.AreEqual(2, keys.Count); Verify.AreEqual(2, values.Count); if (keys[0].Equals(key)) { Verify.AreEqual(keys[1], key2); Verify.AreEqual(values[0], value); Verify.AreEqual(values[1], value2); } else { Verify.AreEqual(keys[0], key2); Verify.AreEqual(keys[1], key); Verify.AreEqual(values[0], value2); Verify.AreEqual(values[1], value); } Verify.IsTrue(cacheDictionary.ContainsKey(key)); Verify.IsTrue(cacheDictionary.ContainsKey(key2)); Verify.IsFalse(cacheDictionary.ContainsKey(key3)); Verify.IsTrue(cacheDictionary.Contains(new KeyValuePair<TokenCacheKey, AuthenticationResult>(key, value))); Verify.IsTrue(cacheDictionary.Contains(new KeyValuePair<TokenCacheKey, AuthenticationResult>(key2, value2))); Verify.IsFalse(cacheDictionary.Contains(new KeyValuePair<TokenCacheKey, AuthenticationResult>(key, value2))); Verify.IsFalse(cacheDictionary.Contains(new KeyValuePair<TokenCacheKey, AuthenticationResult>(key2, value))); try { AddToDictionary(tokenCache, key, value); Verify.Fail("Exception expected due to duplicate key"); } catch (ArgumentException) { // Expected } AddToDictionary(tokenCache, key3, value); Verify.AreEqual(3, cacheDictionary.Keys.Count); Verify.IsTrue(cacheDictionary.ContainsKey(key3)); var cacheItemsCopy = new KeyValuePair<TokenCacheKey, AuthenticationResult>[cacheDictionary.Count + 1]; cacheDictionary.CopyTo(cacheItemsCopy, 1); for (int i = 0; i < cacheDictionary.Count; i++) { Verify.AreEqual(cacheItemsCopy[i + 1].Value, cacheDictionary[cacheItemsCopy[i + 1].Key]); } try { cacheDictionary.CopyTo(cacheItemsCopy, 2); Verify.Fail("Exception expected"); } catch (ArgumentException) { // Expected } try { cacheDictionary.CopyTo(cacheItemsCopy, -1); Verify.Fail("Exception expected"); } catch (ArgumentOutOfRangeException) { // Expected } RemoveFromDictionary(tokenCache, key2); Verify.AreEqual(2, cacheDictionary.Keys.Count); foreach (var kvp in cacheDictionary) { Verify.IsTrue(kvp.Key.Equals(key) || kvp.Key.Equals(key3)); Verify.IsTrue(kvp.Value.Equals(value)); } AuthenticationResult cacheValue; Verify.IsTrue(cacheDictionary.TryGetValue(key, out cacheValue)); Verify.AreEqual(cacheValue, value); Verify.IsTrue(cacheDictionary.TryGetValue(key3, out cacheValue)); Verify.AreEqual(cacheValue, value); Verify.IsFalse(cacheDictionary.TryGetValue(key2, out cacheValue)); cacheDictionary.Clear(); Verify.AreEqual(0, cacheDictionary.Keys.Count); }
public static async Task TokenCacheKeyTestAsync() { CheckPublicGetSets(); string authority = "https://www.gotJwt.com/"; string clientId = Guid.NewGuid().ToString(); string resource = Guid.NewGuid().ToString(); string tenantId = Guid.NewGuid().ToString(); string uniqueId = Guid.NewGuid().ToString(); string displayableId = Guid.NewGuid().ToString(); Uri redirectUri = new Uri("https://www.GetJwt.com"); var authenticationResult = CreateCacheValue(uniqueId, displayableId); authority = authority + tenantId + "/"; UserCredential credential = new UserCredential(displayableId); AuthenticationContext tempContext = new AuthenticationContext(authority, false); var localCache = tempContext.TokenCache; localCache.Clear(); // @Resource, Credential TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, resource, clientId, TokenSubjectType.User, uniqueId, displayableId); AddToDictionary(localCache, tokenCacheKey, authenticationResult); AuthenticationContext acWithLocalCache = new AuthenticationContext(authority, false, localCache); AuthenticationResult authenticationResultFromCache = await acWithLocalCache.AcquireTokenAsync(resource, clientId, credential); AreAuthenticationResultsEqual(authenticationResult, authenticationResultFromCache); // Duplicate throws error authenticationResult.UserInfo.UniqueId = null; AddToDictionary(localCache, new TokenCacheKey(authority, resource, clientId, TokenSubjectType.User, null, displayableId), authenticationResult); try { var result = await acWithLocalCache.AcquireTokenAsync(resource, clientId, credential); #if TEST_ADAL_WINRT_UNIT // ADAL WinRT does not throw exception. It returns error. Verify.AreEqual("multiple_matching_tokens_detected", result.Error); #else Verify.Fail("Exception expected"); #endif } catch (AdalException adae) { Verify.IsTrue(adae.ErrorCode == "multiple_matching_tokens_detected" && adae.Message.Contains("The cache contains multiple tokens satisfying the requirements")); } try { AuthenticationContext acWithDefaultCache = new AuthenticationContext(authority, false); var result = await acWithDefaultCache.AcquireTokenAsync(resource, clientId, credential); #if TEST_ADAL_WINRT_UNIT Verify.AreEqual("multiple_matching_tokens_detected", result.Error); #else Verify.Fail("Exception expected"); #endif } catch (AdalException adae) { Verify.IsTrue(adae.ErrorCode == "multiple_matching_tokens_detected" && adae.Message.Contains("The cache contains multiple tokens satisfying the requirements")); } // @resource && @clientId acWithLocalCache = new AuthenticationContext(authority, false, localCache); localCache.Clear(); var cacheValue = CreateCacheValue(uniqueId, displayableId); resource = Guid.NewGuid().ToString(); clientId = Guid.NewGuid().ToString(); TokenCacheKey tempKey = new TokenCacheKey(authority, resource, clientId, TokenSubjectType.User, null, null); AddToDictionary(localCache, tempKey, cacheValue); RemoveFromDictionary(localCache, tempKey); Verify.IsFalse(localCache.tokenCacheDictionary.ContainsKey(tempKey)); AddToDictionary(localCache, tempKey, cacheValue); #if TEST_ADAL_WINRT_UNIT authenticationResultFromCache = await acWithLocalCache.AcquireTokenAsync(resource, clientId, redirectUri); #else authenticationResultFromCache = await acWithLocalCache.AcquireTokenSilentAsync(resource, clientId); #endif VerifyAuthenticationResultsAreEqual(cacheValue, authenticationResultFromCache); // @resource && @clientId && userId acWithLocalCache = new AuthenticationContext(authority, false, localCache); localCache.Clear(); resource = Guid.NewGuid().ToString(); clientId = Guid.NewGuid().ToString(); uniqueId = Guid.NewGuid().ToString(); displayableId = Guid.NewGuid().ToString(); cacheValue = CreateCacheValue(uniqueId, displayableId); AddToDictionary(localCache, new TokenCacheKey(authority, resource, clientId, TokenSubjectType.User, uniqueId, displayableId), cacheValue); var userId = new UserIdentifier(uniqueId, UserIdentifierType.UniqueId); var userIdUpper = new UserIdentifier(displayableId.ToUpper(), UserIdentifierType.RequiredDisplayableId); #if TEST_ADAL_WINRT_UNIT authenticationResultFromCache = await acWithLocalCache.AcquireTokenAsync(resource, clientId, redirectUri, PromptBehavior.Auto, userId); #else authenticationResultFromCache = await acWithLocalCache.AcquireTokenSilentAsync(resource, clientId, userId); #endif VerifyAuthenticationResultsAreEqual(cacheValue, authenticationResultFromCache); #if TEST_ADAL_WINRT_UNIT authenticationResultFromCache = await acWithLocalCache.AcquireTokenAsync(resource, clientId, redirectUri, PromptBehavior.Auto, userIdUpper); #else authenticationResultFromCache = await acWithLocalCache.AcquireTokenSilentAsync(resource, clientId, userIdUpper); #endif VerifyAuthenticationResultsAreEqual(cacheValue, authenticationResultFromCache); #if TEST_ADAL_WINRT_UNIT authenticationResultFromCache = await acWithLocalCache.AcquireTokenAsync(resource, clientId, redirectUri); #else authenticationResultFromCache = await acWithLocalCache.AcquireTokenSilentAsync(resource, clientId); #endif VerifyAuthenticationResultsAreEqual(cacheValue, authenticationResultFromCache); }
/// <summary> /// Determines whether the specified object is equal to the current object. /// </summary> /// <returns> /// true if the specified object is equal to the current object; otherwise, false. /// </returns> /// <param name="obj">The object to compare with the current object. </param><filterpriority>2</filterpriority> public override bool Equals(object obj) { TokenCacheKey other = obj as TokenCacheKey; return((other != null) && this.Equals(other)); }
internal bool Match(TokenCacheKey key) { return (key.Authority == this.Authority && key.ResourceEquals(this.Resource) && key.ClientIdEquals(this.ClientId) && key.TokenSubjectType == this.TokenSubjectType && key.UniqueId == this.UniqueId && key.DisplayableIdEquals(this.DisplayableId)); }
/// <summary> /// Deserializes state of the cache. The state should be the blob received earlier by calling the method Serialize. /// </summary> /// <param name="state">State of the cache as a blob</param> public void Deserialize([ReadOnlyArray] byte[] state) { lock (cacheLock) { if (state == null) { this.tokenCacheDictionary.Clear(); return; } using (Stream stream = new MemoryStream()) { BinaryWriter writer = new BinaryWriter(stream); writer.Write(state); writer.Flush(); stream.Position = 0; BinaryReader reader = new BinaryReader(stream); int schemaVersion = reader.ReadInt32(); if (schemaVersion != SchemaVersion) { Logger.Warning(null, "The version of the persistent state of the cache does not match the current schema, so skipping deserialization."); return; } this.tokenCacheDictionary.Clear(); int count = reader.ReadInt32(); for (int n = 0; n < count; n++) { string keyString = reader.ReadString(); string[] kvpElements = keyString.Split(new[] {Delimiter}, StringSplitOptions.None); AuthenticationResult result = AuthenticationResult.Deserialize(reader.ReadString()); TokenCacheKey key = new TokenCacheKey(kvpElements[0], kvpElements[1], kvpElements[2], (TokenSubjectType) int.Parse(kvpElements[3]), result.UserInfo); this.tokenCacheDictionary.Add(key, result); } Logger.Information(null, "Deserialized {0} items to token cache.", count); } } }
internal static void TokenCacheValueSplitTest() { var tokenCache = new TokenCache(); TokenCacheKey key = new TokenCacheKey("https://localhost/MockSts", "resourc1", "client1", TokenSubjectType.User, null, "user1"); tokenCache.Clear(); AddToDictionary(tokenCache, key, null); Verify.AreEqual(tokenCache.tokenCacheDictionary[key], null); for (int len = 0; len < 3000; len++) { var value = CreateCacheValue(null, "user1"); tokenCache.Clear(); AddToDictionary(tokenCache, key, value); Verify.AreEqual(tokenCache.tokenCacheDictionary[key], value); } }
internal void StoreToCache(AuthenticationResult result, string authority, string resource, string clientId, TokenSubjectType subjectType, CallState callState) { lock (cacheLock) { Logger.Verbose(callState, "Storing token in the cache..."); string uniqueId = (result.UserInfo != null) ? result.UserInfo.UniqueId : null; string displayableId = (result.UserInfo != null) ? result.UserInfo.DisplayableId : null; this.OnBeforeWrite(new TokenCacheNotificationArgs { Resource = resource, ClientId = clientId, UniqueId = uniqueId, DisplayableId = displayableId }); TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, resource, clientId, subjectType, result.UserInfo); this.tokenCacheDictionary[tokenCacheKey] = result; Logger.Verbose(callState, "An item was stored in the cache"); this.UpdateCachedMrrtRefreshTokens(result, authority, clientId, subjectType); this.HasStateChanged = true; } }
public static void CheckPublicGetSets() { DateTimeOffset now = DateTimeOffset.UtcNow; TokenCacheKey tokenCacheKey = new TokenCacheKey("Authority", "Resource", "ClientId", TokenSubjectType.User, "UniqueId", "DisplayableId"); Verify.IsTrue(tokenCacheKey.Authority == "Authority"); Verify.IsTrue(tokenCacheKey.ClientId == "ClientId"); Verify.IsTrue(tokenCacheKey.Resource == "Resource"); Verify.IsTrue(tokenCacheKey.UniqueId == "UniqueId"); Verify.IsTrue(tokenCacheKey.DisplayableId == "DisplayableId"); Verify.IsTrue(tokenCacheKey.TokenSubjectType == TokenSubjectType.User); }
internal static void TokenCacheCapacityTest() { var tokenCache = new TokenCache(); tokenCache.Clear(); const int MaxItemCount = 100; const int MaxFieldSize = 256; TokenCacheKey[] keys = new TokenCacheKey[MaxItemCount]; AuthenticationResult[] values = new AuthenticationResult[MaxItemCount]; for (int i = 0; i < MaxItemCount; i++) { keys[i] = GenerateRandomTokenCacheKey(MaxFieldSize); values[i] = CreateCacheValue(null, null); AddToDictionary(tokenCache, keys[i], values[i]); } Verify.AreEqual(MaxItemCount, tokenCache.Count); for (int i = 0; i < MaxItemCount; i++) { AuthenticationResult cacheValue; int index = MaxItemCount - i - 1; Verify.IsTrue(tokenCache.tokenCacheDictionary.TryGetValue(keys[index], out cacheValue)); Verify.AreEqual(values[index], cacheValue); RemoveFromDictionary(tokenCache, keys[index]); Verify.AreEqual(index, tokenCache.Count); } tokenCache.Clear(); }
/// <summary> /// Determines whether the specified TokenCacheKey is equal to the current object. /// </summary> /// <returns> /// true if the specified TokenCacheKey is equal to the current object; otherwise, false. /// </returns> /// <param name="other">The TokenCacheKey to compare with the current object. </param><filterpriority>2</filterpriority> public bool Equals(TokenCacheKey other) { return ReferenceEquals(this, other) || (other != null && (other.Authority == this.Authority) && this.ResourceEquals(other.Resource) && this.ClientIdEquals(other.ClientId) && (other.UniqueId == this.UniqueId) && this.DisplayableIdEquals(other.DisplayableId) && (other.TokenSubjectType == this.TokenSubjectType)); }