< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Security.SecurityContextTokenCache
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/SecurityContextTokenCache.cs
Line coverage
37%
Covered lines: 45
Uncovered lines: 76
Coverable lines: 121
Total lines: 342
Line coverage: 37.1%
Branch coverage
25%
Covered branches: 18
Total branches: 70
Branch coverage: 25.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%11100%
.ctor(...)100%11100%
.ctor(...)100%110%
AddContext(...)100%11100%
TryAddContext(...)100%110%
TryAddContext(...)31.25%161638.88%
GetHashKey(...)50%2266.66%
ClearContexts()100%110%
GetContext(...)50%4480%
RemoveContext(...)0%660%
GetMatchingKeys(...)80%101088.88%
RemoveAllContexts(...)100%22100%
UpdateContextCachingTime(...)0%220%
GetAllContexts(...)0%440%
OnQuotaReached(...)0%880%
Compare(...)0%10100%
OnRemove(...)100%11100%
.ctor(...)100%110%
GetHashCode()100%110%
Equals(...)0%440%
op_Equality(...)0%220%
op_Inequality(...)100%110%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/SecurityContextTokenCache.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections;
 6using System.Collections.Generic;
 7using System.Collections.ObjectModel;
 8using System.Xml;
 9using CoreWCF.Runtime;
 10using CoreWCF.Security.Tokens;
 11
 12namespace CoreWCF.Security
 13{
 14    // This is the in-memory cache used for caching SCTs
 15    internal sealed class SecurityContextTokenCache : TimeBoundedCache
 16    {
 17        // if there are less than lowWaterMark entries, no purging is done
 18        private const int LowWaterMark = 50;
 19
 20        // frequency of purging the cache of stale entries
 21        // this is set to 10 mins as SCTs are expected to have long lifetimes
 322        private static TimeSpan s_purgingInterval = TimeSpan.FromMinutes(10);
 23        private const double PruningFactor = 0.20;
 2324        private readonly bool _replaceOldestEntries = true;
 325        private static readonly SctEffectiveTimeComparer s_sctEffectiveTimeComparer = new SctEffectiveTimeComparer();
 26        private TimeSpan _clockSkew;
 27
 28        public SecurityContextTokenCache(int capacity, bool replaceOldestEntries)
 029            : this(capacity, replaceOldestEntries, SecurityProtocolFactory.defaultMaxClockSkew)
 30        {
 031        }
 32
 33        public SecurityContextTokenCache(int capacity, bool replaceOldestEntries, TimeSpan clockSkew)
 2334            : base(LowWaterMark, capacity, null, PurgingMode.TimerBasedPurge, s_purgingInterval, true)
 35
 36        {
 2337            _replaceOldestEntries = replaceOldestEntries;
 2338            _clockSkew = clockSkew;
 2339        }
 40
 41        public void AddContext(SecurityContextSecurityToken token)
 42        {
 1043            TryAddContext(token, true);
 1044        }
 45
 46        public bool TryAddContext(SecurityContextSecurityToken token)
 47        {
 048            return TryAddContext(token, false);
 49        }
 50
 51        private bool TryAddContext(SecurityContextSecurityToken token, bool throwOnFailure)
 52        {
 1053            if (token == null)
 54            {
 055                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(token));
 56            }
 57
 1058            if (!SecurityUtils.IsCurrentlyTimeEffective(token.ValidFrom, token.ValidTo, _clockSkew))
 59            {
 060                if (token.KeyGeneration == null)
 61                {
 062                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.Format(SR.SecurityContextExpiredNoKe
 63                }
 64                else
 65                {
 066                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.Format(SR.SecurityContextExpired, to
 67                }
 68            }
 69
 1070            if (!SecurityUtils.IsCurrentlyTimeEffective(token.KeyEffectiveTime, token.KeyExpirationTime, _clockSkew))
 71            {
 072                if (token.KeyGeneration == null)
 73                {
 074                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.Format(SR.SecurityContextKeyExpiredN
 75                }
 76                else
 77                {
 078                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.Format(SR.SecurityContextKeyExpired,
 79                }
 80            }
 81
 1082            object hashKey = GetHashKey(token.ContextId, token.KeyGeneration);
 1083            bool wasTokenAdded = TryAddItem(hashKey, (SecurityContextSecurityToken)token.Clone(), false);
 1084            if (!wasTokenAdded)
 85            {
 086                if (throwOnFailure)
 87                {
 088                    if (token.KeyGeneration == null)
 89                    {
 090                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Forma
 91                    }
 92                    else
 93                    {
 094                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Forma
 95                    }
 96                }
 97            }
 1098            return wasTokenAdded;
 99        }
 100
 101        private object GetHashKey(UniqueId contextId, UniqueId generation)
 102        {
 30103            if (generation == null)
 104            {
 30105                return contextId;
 106            }
 107            else
 108            {
 0109                return new ContextAndGenerationKey(contextId, generation);
 110            }
 111        }
 112
 113        public void ClearContexts()
 114        {
 0115            ClearItems();
 0116        }
 117
 118        public SecurityContextSecurityToken GetContext(UniqueId contextId, UniqueId generation)
 119        {
 20120            if (contextId == null)
 121            {
 0122                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(contextId));
 123            }
 20124            object hashKey = GetHashKey(contextId, generation);
 20125            SecurityContextSecurityToken sct = (SecurityContextSecurityToken)GetItem(hashKey);
 20126            return sct != null ? (SecurityContextSecurityToken)sct.Clone() : null;
 127        }
 128
 129        public void RemoveContext(UniqueId contextId, UniqueId generation, bool throwIfNotPresent)
 130        {
 0131            if (contextId == null)
 132            {
 0133                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(contextId));
 134            }
 0135            object hashKey = GetHashKey(contextId, generation);
 0136            if (!TryRemoveItem(hashKey) && throwIfNotPresent)
 137            {
 0138                if (generation == null)
 139                {
 0140                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR
 141                }
 142                else
 143                {
 0144                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR
 145                }
 146            }
 0147        }
 148
 149        private ArrayList GetMatchingKeys(UniqueId contextId)
 150        {
 10151            if (contextId == null)
 152            {
 0153                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(contextId));
 154            }
 10155            ArrayList matchingKeys = new ArrayList(2);
 156
 10157            bool lockHeld = false;
 158            try
 159            {
 10160                try { }
 161                finally
 162                {
 10163                    CacheLock.AcquireReaderLock(-1);
 10164                    lockHeld = true;
 10165                }
 40166                foreach (object key in Entries.Keys)
 167                {
 168                    bool isMatch;
 10169                    if (key is UniqueId)
 170                    {
 10171                        isMatch = (((UniqueId)key) == contextId);
 172                    }
 173                    else
 174                    {
 0175                        isMatch = (((ContextAndGenerationKey)key).ContextId == contextId);
 176                    }
 10177                    if (isMatch)
 178                    {
 10179                        matchingKeys.Add(key);
 180                    }
 181                }
 182            }
 183            finally
 184            {
 10185                if (lockHeld)
 186                {
 10187                    CacheLock.ReleaseReaderLock();
 188                }
 10189            }
 10190            return matchingKeys;
 191        }
 192
 193        public void RemoveAllContexts(UniqueId contextId)
 194        {
 10195            ArrayList matchingKeys = GetMatchingKeys(contextId);
 40196            for (int i = 0; i < matchingKeys.Count; ++i)
 197            {
 10198                TryRemoveItem(matchingKeys[i]);
 199            }
 10200        }
 201
 202        public void UpdateContextCachingTime(SecurityContextSecurityToken token, DateTime expirationTime)
 203        {
 0204            if (token.ValidTo <= expirationTime.ToUniversalTime())
 205            {
 0206                return;
 207            }
 0208            TryReplaceItem(GetHashKey(token.ContextId, token.KeyGeneration), token, expirationTime);
 0209        }
 210
 211        public Collection<SecurityContextSecurityToken> GetAllContexts(UniqueId contextId)
 212        {
 0213            ArrayList matchingKeys = GetMatchingKeys(contextId);
 214
 0215            Collection<SecurityContextSecurityToken> matchingContexts = new Collection<SecurityContextSecurityToken>();
 0216            for (int i = 0; i < matchingKeys.Count; ++i)
 217            {
 0218                if (GetItem(matchingKeys[i]) is SecurityContextSecurityToken token)
 219                {
 0220                    matchingContexts.Add(token);
 221                }
 222            }
 0223            return matchingContexts;
 224        }
 225
 226        protected override ArrayList OnQuotaReached(Hashtable cacheTable)
 227        {
 0228            if (!_replaceOldestEntries)
 229            {
 230                //SecurityTraceRecordHelper.TraceSecurityContextTokenCacheFull(this.Capacity, 0);
 0231                return base.OnQuotaReached(cacheTable);
 232            }
 233            else
 234            {
 0235                List<SecurityContextSecurityToken> tokens = new List<SecurityContextSecurityToken>(cacheTable.Count);
 0236                foreach (IExpirableItem value in cacheTable.Values)
 237                {
 0238                    SecurityContextSecurityToken token = (SecurityContextSecurityToken)ExtractItem(value);
 0239                    tokens.Add(token);
 240                }
 0241                tokens.Sort(s_sctEffectiveTimeComparer);
 0242                int pruningAmount = (int)(((double)Capacity) * PruningFactor);
 0243                pruningAmount = pruningAmount <= 0 ? Capacity : pruningAmount;
 0244                ArrayList keys = new ArrayList(pruningAmount);
 0245                for (int i = 0; i < pruningAmount; ++i)
 246                {
 0247                    keys.Add(GetHashKey(tokens[i].ContextId, tokens[i].KeyGeneration));
 0248                    OnRemove(tokens[i]);
 249                }
 250                //  SecurityTraceRecordHelper.TraceSecurityContextTokenCacheFull(this.Capacity, pruningAmount);
 0251                return keys;
 252            }
 253        }
 254
 255        private sealed class SctEffectiveTimeComparer : IComparer<SecurityContextSecurityToken>
 256        {
 257            public int Compare(SecurityContextSecurityToken sct1, SecurityContextSecurityToken sct2)
 258            {
 0259                if (sct1 == sct2)
 260                {
 0261                    return 0;
 262                }
 0263                if (sct1.ValidFrom.ToUniversalTime() < sct2.ValidFrom.ToUniversalTime())
 264                {
 0265                    return -1;
 266                }
 0267                else if (sct1.ValidFrom.ToUniversalTime() > sct2.ValidFrom.ToUniversalTime())
 268                {
 0269                    return 1;
 270                }
 271                else
 272                {
 273                    // compare the key effective times
 0274                    if (sct1.KeyEffectiveTime.ToUniversalTime() < sct2.KeyEffectiveTime.ToUniversalTime())
 275                    {
 0276                        return -1;
 277                    }
 0278                    else if (sct1.KeyEffectiveTime.ToUniversalTime() > sct2.KeyEffectiveTime.ToUniversalTime())
 279                    {
 0280                        return 1;
 281                    }
 282                    else
 283                    {
 0284                        return 0;
 285                    }
 286                }
 287            }
 288        }
 289
 290        protected override void OnRemove(object item)
 291        {
 10292            ((IDisposable)item).Dispose();
 10293            base.OnRemove(item);
 10294        }
 295
 296        private struct ContextAndGenerationKey
 297        {
 298            public ContextAndGenerationKey(UniqueId contextId, UniqueId generation)
 299            {
 300                Fx.Assert(contextId != null && generation != null, "");
 0301                ContextId = contextId;
 0302                Generation = generation;
 0303            }
 304
 0305            public UniqueId ContextId { get; }
 306
 0307            public UniqueId Generation { get; }
 308
 309            public override int GetHashCode()
 310            {
 0311                return ContextId.GetHashCode() ^ Generation.GetHashCode();
 312            }
 313
 314            public override bool Equals(object obj)
 315            {
 0316                if (obj is ContextAndGenerationKey key2)
 317                {
 0318                    return (key2.ContextId == ContextId && key2.Generation == Generation);
 319                }
 320                else
 321                {
 0322                    return false;
 323                }
 324            }
 325
 326            public static bool operator ==(ContextAndGenerationKey a, ContextAndGenerationKey b)
 327            {
 0328                if (ReferenceEquals(a, null))
 329                {
 0330                    return ReferenceEquals(b, null);
 331                }
 332
 0333                return (a.Equals(b));
 334            }
 335
 336            public static bool operator !=(ContextAndGenerationKey a, ContextAndGenerationKey b)
 337            {
 0338                return !(a == b);
 339            }
 340        }
 341    }
 342}