| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- //-----------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- namespace System.ServiceModel.Security
- {
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Runtime;
- using System.ServiceModel.Diagnostics;
- using System.ServiceModel.Security.Tokens;
- using System.Xml;
- // This is the in-memory cache used for caching SCTs
- sealed class SecurityContextTokenCache : TimeBoundedCache
- {
- // if there are less than lowWaterMark entries, no purging is done
- static int lowWaterMark = 50;
- // frequency of purging the cache of stale entries
- // this is set to 10 mins as SCTs are expected to have long lifetimes
- static TimeSpan purgingInterval = TimeSpan.FromMinutes(10);
- static double pruningFactor = 0.20;
- bool replaceOldestEntries = true;
- static SctEffectiveTimeComparer sctEffectiveTimeComparer = new SctEffectiveTimeComparer();
- TimeSpan clockSkew;
- public SecurityContextTokenCache( int capacity, bool replaceOldestEntries )
- : this( capacity, replaceOldestEntries, SecurityProtocolFactory.defaultMaxClockSkew )
- {
- }
- public SecurityContextTokenCache(int capacity, bool replaceOldestEntries, TimeSpan clockSkew)
- : base(lowWaterMark, capacity, null, PurgingMode.TimerBasedPurge, purgingInterval, true)
- {
- this.replaceOldestEntries = replaceOldestEntries;
- this.clockSkew = clockSkew;
- }
- public void AddContext(SecurityContextSecurityToken token)
- {
- TryAddContext(token, true);
- }
-
- public bool TryAddContext(SecurityContextSecurityToken token)
- {
- return TryAddContext(token, false);
- }
- bool TryAddContext(SecurityContextSecurityToken token, bool throwOnFailure)
- {
- if (token == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("token");
- }
- if ( !SecurityUtils.IsCurrentlyTimeEffective( token.ValidFrom, token.ValidTo, this.clockSkew ) )
- {
- if (token.KeyGeneration == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SecurityContextExpiredNoKeyGeneration, token.ContextId));
- else
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SecurityContextExpired, token.ContextId, token.KeyGeneration.ToString()));
- }
- if ( !SecurityUtils.IsCurrentlyTimeEffective( token.KeyEffectiveTime, token.KeyExpirationTime, this.clockSkew ) )
- {
- if (token.KeyGeneration == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SecurityContextKeyExpiredNoKeyGeneration, token.ContextId));
- else
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SecurityContextKeyExpired, token.ContextId, token.KeyGeneration.ToString()));
- }
- object hashKey = GetHashKey(token.ContextId, token.KeyGeneration);
- bool wasTokenAdded = base.TryAddItem(hashKey, (SecurityContextSecurityToken)token.Clone(), false);
- if (!wasTokenAdded)
- {
- if (throwOnFailure)
- {
- if (token.KeyGeneration == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ContextAlreadyRegisteredNoKeyGeneration, token.ContextId)));
- else
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ContextAlreadyRegistered, token.ContextId, token.KeyGeneration.ToString())));
- }
- }
- return wasTokenAdded;
- }
- object GetHashKey(UniqueId contextId, UniqueId generation)
- {
- if (generation == null)
- {
- return contextId;
- }
- else
- {
- return new ContextAndGenerationKey(contextId, generation);
- }
- }
- public void ClearContexts()
- {
- base.ClearItems();
- }
- public SecurityContextSecurityToken GetContext(UniqueId contextId, UniqueId generation)
- {
- if (contextId == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contextId");
- }
- object hashKey = GetHashKey(contextId, generation);
- SecurityContextSecurityToken sct = (SecurityContextSecurityToken)base.GetItem(hashKey);
- return sct != null ? (SecurityContextSecurityToken)sct.Clone() : null;
- }
- public void RemoveContext(UniqueId contextId, UniqueId generation, bool throwIfNotPresent)
- {
- if (contextId == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contextId");
- }
- object hashKey = GetHashKey(contextId, generation);
- if (!base.TryRemoveItem(hashKey) && throwIfNotPresent)
- {
- if (generation == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ContextNotPresentNoKeyGeneration, contextId)));
- else
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ContextNotPresent, contextId, generation.ToString())));
- }
- }
- ArrayList GetMatchingKeys(UniqueId contextId)
- {
- if (contextId == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contextId");
- }
- ArrayList matchingKeys = new ArrayList(2);
- bool lockHeld = false;
- try
- {
- try { }
- finally
- {
- base.CacheLock.AcquireReaderLock(-1);
- lockHeld = true;
- }
- foreach (object key in this.Entries.Keys)
- {
- bool isMatch = false;
- if (key is UniqueId)
- {
- isMatch = (((UniqueId)key) == contextId);
- }
- else
- {
- isMatch = (((ContextAndGenerationKey)key).ContextId == contextId);
- }
- if (isMatch)
- {
- matchingKeys.Add(key);
- }
- }
- }
- finally
- {
- if (lockHeld)
- {
- base.CacheLock.ReleaseReaderLock();
- }
- }
- return matchingKeys;
- }
- public void RemoveAllContexts(UniqueId contextId)
- {
- ArrayList matchingKeys = GetMatchingKeys(contextId);
- for (int i = 0; i < matchingKeys.Count; ++i)
- {
- base.TryRemoveItem(matchingKeys[i]);
- }
- }
- public void UpdateContextCachingTime(SecurityContextSecurityToken token, DateTime expirationTime)
- {
- if (token.ValidTo <= expirationTime.ToUniversalTime())
- {
- return;
- }
- base.TryReplaceItem(GetHashKey(token.ContextId, token.KeyGeneration), token, expirationTime);
- }
- public Collection<SecurityContextSecurityToken> GetAllContexts(UniqueId contextId)
- {
- ArrayList matchingKeys = GetMatchingKeys(contextId);
- Collection<SecurityContextSecurityToken> matchingContexts = new Collection<SecurityContextSecurityToken>();
- for (int i = 0; i < matchingKeys.Count; ++i)
- {
- SecurityContextSecurityToken token = base.GetItem(matchingKeys[i]) as SecurityContextSecurityToken;
- if (token != null)
- {
- matchingContexts.Add(token);
- }
- }
- return matchingContexts;
- }
- protected override ArrayList OnQuotaReached(Hashtable cacheTable)
- {
- if (!this.replaceOldestEntries)
- {
- SecurityTraceRecordHelper.TraceSecurityContextTokenCacheFull(this.Capacity, 0);
- return base.OnQuotaReached(cacheTable);
- }
- else
- {
- List<SecurityContextSecurityToken> tokens = new List<SecurityContextSecurityToken>(cacheTable.Count);
- foreach (IExpirableItem value in cacheTable.Values)
- {
- SecurityContextSecurityToken token = (SecurityContextSecurityToken)ExtractItem(value);
- tokens.Add(token);
- }
- tokens.Sort(sctEffectiveTimeComparer);
- int pruningAmount = (int)(((double)this.Capacity) * pruningFactor);
- pruningAmount = pruningAmount <= 0 ? this.Capacity : pruningAmount;
- ArrayList keys = new ArrayList(pruningAmount);
- for (int i = 0; i < pruningAmount; ++i)
- {
- keys.Add(GetHashKey(tokens[i].ContextId, tokens[i].KeyGeneration));
- OnRemove(tokens[i]);
- }
- SecurityTraceRecordHelper.TraceSecurityContextTokenCacheFull(this.Capacity, pruningAmount);
- return keys;
- }
- }
- sealed class SctEffectiveTimeComparer : IComparer<SecurityContextSecurityToken>
- {
- public int Compare(SecurityContextSecurityToken sct1, SecurityContextSecurityToken sct2)
- {
- if (sct1 == sct2)
- {
- return 0;
- }
- if (sct1.ValidFrom.ToUniversalTime() < sct2.ValidFrom.ToUniversalTime())
- {
- return -1;
- }
- else if (sct1.ValidFrom.ToUniversalTime() > sct2.ValidFrom.ToUniversalTime())
- {
- return 1;
- }
- else
- {
- // compare the key effective times
- if (sct1.KeyEffectiveTime.ToUniversalTime() < sct2.KeyEffectiveTime.ToUniversalTime())
- {
- return -1;
- }
- else if (sct1.KeyEffectiveTime.ToUniversalTime() > sct2.KeyEffectiveTime.ToUniversalTime())
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
- }
- }
- protected override void OnRemove(object item)
- {
- ((IDisposable)item).Dispose();
- base.OnRemove(item);
- }
- struct ContextAndGenerationKey
- {
- UniqueId contextId;
- UniqueId generation;
- public ContextAndGenerationKey(UniqueId contextId, UniqueId generation)
- {
- Fx.Assert(contextId != null && generation != null, "");
- this.contextId = contextId;
- this.generation = generation;
- }
- public UniqueId ContextId
- {
- get
- {
- return this.contextId;
- }
- }
- public UniqueId Generation
- {
- get
- {
- return this.generation;
- }
- }
- public override int GetHashCode()
- {
- return this.contextId.GetHashCode() ^ this.generation.GetHashCode();
- }
- public override bool Equals(object obj)
- {
- if (obj is ContextAndGenerationKey)
- {
- ContextAndGenerationKey key2 = ((ContextAndGenerationKey)obj);
- return (key2.ContextId == this.contextId && key2.Generation == this.generation);
- }
- else
- {
- return false;
- }
- }
- public static bool operator ==(ContextAndGenerationKey a, ContextAndGenerationKey b)
- {
- if (object.ReferenceEquals(a, null))
- {
- return object.ReferenceEquals(b, null);
- }
- return (a.Equals(b));
- }
- public static bool operator !=(ContextAndGenerationKey a, ContextAndGenerationKey b)
- {
- return !(a == b);
- }
- }
- }
- }
|