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; } }
/// <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))); }
/// <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) { PlatformPlugin.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); } PlatformPlugin.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; } }
/// <summary> /// Deletes an item from the cache. /// </summary> /// <param name="item">The item to delete from the cache</param> public virtual void DeleteItem(TokenCacheItem item) { 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); PlatformPlugin.Logger.Information(null, "One item removed successfully"); } else { PlatformPlugin.Logger.Information(null, "Item not Present in the Cache"); } this.HasStateChanged = true; this.OnAfterAccess(args); } }
/// <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)); }
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; bool tokenNearExpiry = (resultEx.Result.ExpiresOn <= DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes)); if (tokenNearExpiry) { resultEx.Result.AccessToken = null; PlatformPlugin.Logger.Verbose(callState, "An expired or near expiry token was found in the cache"); } else if (!cacheKey.ResourceEquals(cacheQueryData.Resource)) { PlatformPlugin.Logger.Verbose(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 { PlatformPlugin.Logger.Verbose(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); } }