< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 172
Coverable lines: 172
Total lines: 389
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 78
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%110%
Add(...)0%12120%
Add(...)0%12120%
Remove(...)0%10100%
Remove(...)0%12120%
GetCredential(...)0%880%
GetCredential(...)0%880%
GetEnumerator()100%110%
Create(...)0%660%
.ctor(...)100%110%
MoveNext()0%220%
MoveNext(...)100%110%
Reset()100%110%
.ctor(...)100%110%
MoveNext(...)100%110%
Reset()100%110%
.ctor(...)100%110%
MoveNext(...)0%440%
Reset()100%110%
MoveNext(...)100%110%
Reset(...)100%110%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Net.Primitives/src/System/Net/CredentialCache.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.Collections;
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Diagnostics.CodeAnalysis;
 8using System.Globalization;
 9
 10namespace System.Net
 11{
 12    // More sophisticated password cache that stores multiple
 13    // name-password pairs and associates these with host/realm.
 14    public class CredentialCache : ICredentials, ICredentialsByHost, IEnumerable
 15    {
 16        private Dictionary<CredentialCacheKey, NetworkCredential>? _cache;
 17        private Dictionary<CredentialHostKey, NetworkCredential>? _cacheForHosts;
 18        private int _version;
 19
 020        public CredentialCache()
 021        {
 022        }
 23
 24        public void Add(Uri uriPrefix, string authType, NetworkCredential cred)
 025        {
 026            ArgumentNullException.ThrowIfNull(uriPrefix);
 027            ArgumentNullException.ThrowIfNull(authType);
 28
 029            if ((cred is SystemNetworkCredential)
 030                && !((string.Equals(authType, NegotiationInfoClass.NTLM, StringComparison.OrdinalIgnoreCase))
 031                     || (string.Equals(authType, NegotiationInfoClass.Kerberos, StringComparison.OrdinalIgnoreCase))
 032                     || (string.Equals(authType, NegotiationInfoClass.Negotiate, StringComparison.OrdinalIgnoreCase)))
 033                )
 034            {
 035                throw new ArgumentException(SR.Format(SR.net_nodefaultcreds, authType), nameof(authType));
 36            }
 37
 038            ++_version;
 39
 040            var key = new CredentialCacheKey(uriPrefix, authType);
 41
 042            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Adding key:[{key}], cred:[{cred.Domain}],[{c
 43
 044            _cache ??= new Dictionary<CredentialCacheKey, NetworkCredential>();
 045            _cache.Add(key, cred);
 046        }
 47
 48        public void Add(string host, int port, string authenticationType, NetworkCredential credential)
 049        {
 050            ArgumentException.ThrowIfNullOrEmpty(host);
 051            ArgumentNullException.ThrowIfNull(authenticationType);
 52
 053            ArgumentOutOfRangeException.ThrowIfNegative(port);
 54
 055            if ((credential is SystemNetworkCredential)
 056                && !((string.Equals(authenticationType, NegotiationInfoClass.NTLM, StringComparison.OrdinalIgnoreCase))
 057                     || (string.Equals(authenticationType, NegotiationInfoClass.Kerberos, StringComparison.OrdinalIgnore
 058                     || (string.Equals(authenticationType, NegotiationInfoClass.Negotiate, StringComparison.OrdinalIgnor
 059                )
 060            {
 061                throw new ArgumentException(SR.Format(SR.net_nodefaultcreds, authenticationType), nameof(authenticationT
 62            }
 63
 064            ++_version;
 65
 066            var key = new CredentialHostKey(host, port, authenticationType);
 67
 068            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Adding key:[{key}], cred:[{credential.Domain
 69
 070            _cacheForHosts ??= new Dictionary<CredentialHostKey, NetworkCredential>();
 071            _cacheForHosts.Add(key, credential);
 072        }
 73
 74        public void Remove(Uri? uriPrefix, string? authType)
 075        {
 076            if (uriPrefix == null || authType == null)
 077            {
 78                // These couldn't possibly have been inserted into
 79                // the cache because of the test in Add().
 080                return;
 81            }
 82
 083            if (_cache == null)
 084            {
 085                if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "Short-circuiting because the dictionary i
 086                return;
 87            }
 88
 089            ++_version;
 90
 091            var key = new CredentialCacheKey(uriPrefix, authType);
 92
 093            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Removing key:[{key}]");
 94
 095            _cache.Remove(key);
 096        }
 97
 98        public void Remove(string? host, int port, string? authenticationType)
 099        {
 0100            if (host == null || authenticationType == null)
 0101            {
 102                // These couldn't possibly have been inserted into
 103                // the cache because of the test in Add().
 0104                return;
 105            }
 106
 0107            if (port < 0)
 0108            {
 0109                return;
 110            }
 111
 0112            if (_cacheForHosts == null)
 0113            {
 0114                if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "Short-circuiting because the dictionary i
 0115                return;
 116            }
 117
 0118            ++_version;
 119
 0120            var key = new CredentialHostKey(host, port, authenticationType);
 121
 0122            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Removing key:[{key}]");
 123
 0124            _cacheForHosts.Remove(key);
 0125        }
 126
 127        public NetworkCredential? GetCredential(Uri uriPrefix, string authType)
 0128        {
 0129            ArgumentNullException.ThrowIfNull(uriPrefix);
 0130            ArgumentNullException.ThrowIfNull(authType);
 131
 0132            if (_cache == null)
 0133            {
 0134                if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "CredentialCache::GetCredential short-circ
 0135                return null;
 136            }
 137
 0138            CredentialCacheHelper.TryGetCredential(_cache, uriPrefix, authType, out _ /*uri*/, out NetworkCredential? mo
 139
 0140            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Returning {(mostSpecificMatch == null ? "nul
 141
 0142            return mostSpecificMatch;
 0143        }
 144
 145        public NetworkCredential? GetCredential(string host, int port, string authenticationType)
 0146        {
 0147            ArgumentException.ThrowIfNullOrEmpty(host);
 0148            ArgumentNullException.ThrowIfNull(authenticationType);
 0149            ArgumentOutOfRangeException.ThrowIfNegative(port);
 150
 0151            if (_cacheForHosts == null)
 0152            {
 0153                if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "CredentialCache::GetCredential short-circ
 0154                return null;
 155            }
 156
 0157            var key = new CredentialHostKey(host, port, authenticationType);
 158
 159            NetworkCredential? match;
 0160            _cacheForHosts.TryGetValue(key, out match);
 161
 0162            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Returning {((match == null) ? "null" : "(" +
 163
 0164            return match;
 0165        }
 166
 0167        public IEnumerator GetEnumerator() => CredentialEnumerator.Create(this);
 168
 0169        public static ICredentials DefaultCredentials => SystemNetworkCredential.s_defaultCredential;
 170
 0171        public static NetworkCredential DefaultNetworkCredentials => SystemNetworkCredential.s_defaultCredential;
 172
 173        private class CredentialEnumerator : IEnumerator
 174        {
 175            internal static CredentialEnumerator Create(CredentialCache cache)
 0176            {
 0177                Debug.Assert(cache != null);
 178
 0179                if (cache._cache != null)
 0180                {
 0181                    return cache._cacheForHosts != null ?
 0182                        new DoubleTableCredentialEnumerator(cache) :
 0183                        new SingleTableCredentialEnumerator<CredentialCacheKey>(cache, cache._cache);
 184                }
 185                else
 0186                {
 0187                    return cache._cacheForHosts != null ?
 0188                        new SingleTableCredentialEnumerator<CredentialHostKey>(cache, cache._cacheForHosts) :
 0189                        new CredentialEnumerator(cache);
 190                }
 0191            }
 192
 193            private readonly CredentialCache _cache;
 194            private readonly int _version;
 195            private bool _enumerating;
 196            private NetworkCredential? _current;
 197
 0198            private CredentialEnumerator(CredentialCache cache)
 0199            {
 0200                Debug.Assert(cache != null);
 201
 0202                _cache = cache;
 0203                _version = cache._version;
 0204            }
 205
 206            public object Current
 207            {
 208                get
 0209                {
 0210                    if (!_enumerating)
 0211                    {
 0212                        throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen);
 213                    }
 0214                    if (_version != _cache._version)
 0215                    {
 0216                        throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
 217                    }
 218
 0219                    return _current!;
 0220                }
 221            }
 222
 223            public bool MoveNext()
 0224            {
 0225                if (_version != _cache._version)
 0226                {
 0227                    throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
 228                }
 229
 0230                return _enumerating = MoveNext(out _current);
 0231            }
 232
 233            protected virtual bool MoveNext(out NetworkCredential? current)
 0234            {
 0235                current = null;
 0236                return false;
 0237            }
 238
 239            public virtual void Reset()
 0240            {
 0241                _enumerating = false;
 0242            }
 243
 244            private class SingleTableCredentialEnumerator<TKey> : CredentialEnumerator where TKey : notnull
 245            {
 246                private Dictionary<TKey, NetworkCredential>.ValueCollection.Enumerator _enumerator; // mutable struct fi
 247
 0248                public SingleTableCredentialEnumerator(CredentialCache cache, Dictionary<TKey, NetworkCredential> table)
 0249                {
 0250                    Debug.Assert(table != null);
 251
 252                    // Despite the ValueCollection allocation, ValueCollection's enumerator is faster
 253                    // than Dictionary's enumerator for enumerating the values because it avoids
 254                    // KeyValuePair copying.
 0255                    _enumerator = table.Values.GetEnumerator();
 0256                }
 257
 258                protected override bool MoveNext(out NetworkCredential current) =>
 0259                    DictionaryEnumeratorHelper.MoveNext(ref _enumerator, out current);
 260
 261                public override void Reset()
 0262                {
 0263                    DictionaryEnumeratorHelper.Reset(ref _enumerator);
 0264                    base.Reset();
 0265                }
 266            }
 267
 268            private sealed class DoubleTableCredentialEnumerator : SingleTableCredentialEnumerator<CredentialCacheKey>
 269            {
 270                private Dictionary<CredentialHostKey, NetworkCredential>.ValueCollection.Enumerator _enumerator; // muta
 271                private bool _onThisEnumerator;
 272
 0273                public DoubleTableCredentialEnumerator(CredentialCache cache) : base(cache, cache._cache!)
 0274                {
 0275                    Debug.Assert(cache._cacheForHosts != null);
 276
 277                    // Despite the ValueCollection allocation, ValueCollection's enumerator is faster
 278                    // than Dictionary's enumerator for enumerating the values because it avoids
 279                    // KeyValuePair copying.
 0280                    _enumerator = cache._cacheForHosts.Values.GetEnumerator();
 0281                }
 282
 283                protected override bool MoveNext(out NetworkCredential current)
 0284                {
 0285                    if (!_onThisEnumerator)
 0286                    {
 0287                        if (base.MoveNext(out current))
 0288                        {
 0289                            return true;
 290                        }
 291                        else
 0292                        {
 0293                            _onThisEnumerator = true;
 0294                        }
 0295                    }
 296
 0297                    return DictionaryEnumeratorHelper.MoveNext(ref _enumerator, out current);
 0298                }
 299
 300                public override void Reset()
 0301                {
 0302                    _onThisEnumerator = false;
 0303                    DictionaryEnumeratorHelper.Reset(ref _enumerator);
 0304                    base.Reset();
 0305                }
 306            }
 307
 308            private static class DictionaryEnumeratorHelper
 309            {
 310                internal static bool MoveNext<TKey, TValue>(ref Dictionary<TKey, TValue>.ValueCollection.Enumerator enum
 0311                {
 0312                    bool result = enumerator.MoveNext();
 0313                    current = enumerator.Current;
 0314                    return result;
 0315                }
 316
 317                // Allows calling Reset on Dictionary's struct enumerator without a box allocation.
 318                internal static void Reset<TEnumerator>(ref TEnumerator enumerator) where TEnumerator : IEnumerator
 0319                {
 320                    // The Dictionary enumerator's Reset method throws if the Dictionary has changed, but
 321                    // CredentialCache.Reset should not throw, so we catch and swallow the exception.
 0322                    try { enumerator.Reset(); } catch (InvalidOperationException) { }
 0323                }
 324            }
 325        }
 326    }
 327
 328    // Abstraction for credentials in password-based
 329    // authentication schemes (basic, digest, NTLM, Kerberos).
 330    //
 331    // Note that this is not applicable to public-key based
 332    // systems such as SSL client authentication.
 333    //
 334    // "Password" here may be the clear text password or it
 335    // could be a one-way hash that is sufficient to
 336    // authenticate, as in HTTP/1.1 digest.
 337    internal sealed class SystemNetworkCredential : NetworkCredential
 338    {
 339        internal static readonly SystemNetworkCredential s_defaultCredential = new SystemNetworkCredential();
 340
 341        // We want reference equality to work. Making this private is a good way to guarantee that.
 342        private SystemNetworkCredential() :
 343            base(string.Empty, string.Empty, string.Empty)
 344        {
 345        }
 346    }
 347
 348    internal readonly struct CredentialHostKey : IEquatable<CredentialHostKey>
 349    {
 350        public readonly string Host;
 351        public readonly string AuthenticationType;
 352        public readonly int Port;
 353
 354        internal CredentialHostKey(string host, int port, string authenticationType)
 355        {
 356            Debug.Assert(!string.IsNullOrEmpty(host));
 357            Debug.Assert(port >= 0);
 358            Debug.Assert(authenticationType != null);
 359
 360            Host = host;
 361            Port = port;
 362            AuthenticationType = authenticationType;
 363        }
 364
 365        public override int GetHashCode() =>
 366            StringComparer.OrdinalIgnoreCase.GetHashCode(AuthenticationType) ^
 367            StringComparer.OrdinalIgnoreCase.GetHashCode(Host) ^
 368            Port.GetHashCode();
 369
 370        public bool Equals(CredentialHostKey other)
 371        {
 372            bool equals =
 373                string.Equals(AuthenticationType, other.AuthenticationType, StringComparison.OrdinalIgnoreCase) &&
 374                string.Equals(Host, other.Host, StringComparison.OrdinalIgnoreCase) &&
 375                Port == other.Port;
 376
 377            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Equals({this},{other}) returns {equals}");
 378
 379            return equals;
 380        }
 381
 382        public override bool Equals([NotNullWhen(true)] object? obj) =>
 383            obj is CredentialHostKey && Equals((CredentialHostKey)obj);
 384
 385        public override string ToString() =>
 386            string.Create(CultureInfo.InvariantCulture, $"{Host}:{Port}:{AuthenticationType}");
 387    }
 388}
 389