< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 21
Coverable lines: 21
Total lines: 389
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 8
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%
GetHashCode()100%110%
Equals(...)0%660%
Equals(...)0%220%
ToString()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
 20        public CredentialCache()
 21        {
 22        }
 23
 24        public void Add(Uri uriPrefix, string authType, NetworkCredential cred)
 25        {
 26            ArgumentNullException.ThrowIfNull(uriPrefix);
 27            ArgumentNullException.ThrowIfNull(authType);
 28
 29            if ((cred is SystemNetworkCredential)
 30                && !((string.Equals(authType, NegotiationInfoClass.NTLM, StringComparison.OrdinalIgnoreCase))
 31                     || (string.Equals(authType, NegotiationInfoClass.Kerberos, StringComparison.OrdinalIgnoreCase))
 32                     || (string.Equals(authType, NegotiationInfoClass.Negotiate, StringComparison.OrdinalIgnoreCase)))
 33                )
 34            {
 35                throw new ArgumentException(SR.Format(SR.net_nodefaultcreds, authType), nameof(authType));
 36            }
 37
 38            ++_version;
 39
 40            var key = new CredentialCacheKey(uriPrefix, authType);
 41
 42            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Adding key:[{key}], cred:[{cred.Domain}],[{c
 43
 44            _cache ??= new Dictionary<CredentialCacheKey, NetworkCredential>();
 45            _cache.Add(key, cred);
 46        }
 47
 48        public void Add(string host, int port, string authenticationType, NetworkCredential credential)
 49        {
 50            ArgumentException.ThrowIfNullOrEmpty(host);
 51            ArgumentNullException.ThrowIfNull(authenticationType);
 52
 53            ArgumentOutOfRangeException.ThrowIfNegative(port);
 54
 55            if ((credential is SystemNetworkCredential)
 56                && !((string.Equals(authenticationType, NegotiationInfoClass.NTLM, StringComparison.OrdinalIgnoreCase))
 57                     || (string.Equals(authenticationType, NegotiationInfoClass.Kerberos, StringComparison.OrdinalIgnore
 58                     || (string.Equals(authenticationType, NegotiationInfoClass.Negotiate, StringComparison.OrdinalIgnor
 59                )
 60            {
 61                throw new ArgumentException(SR.Format(SR.net_nodefaultcreds, authenticationType), nameof(authenticationT
 62            }
 63
 64            ++_version;
 65
 66            var key = new CredentialHostKey(host, port, authenticationType);
 67
 68            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Adding key:[{key}], cred:[{credential.Domain
 69
 70            _cacheForHosts ??= new Dictionary<CredentialHostKey, NetworkCredential>();
 71            _cacheForHosts.Add(key, credential);
 72        }
 73
 74        public void Remove(Uri? uriPrefix, string? authType)
 75        {
 76            if (uriPrefix == null || authType == null)
 77            {
 78                // These couldn't possibly have been inserted into
 79                // the cache because of the test in Add().
 80                return;
 81            }
 82
 83            if (_cache == null)
 84            {
 85                if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "Short-circuiting because the dictionary i
 86                return;
 87            }
 88
 89            ++_version;
 90
 91            var key = new CredentialCacheKey(uriPrefix, authType);
 92
 93            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Removing key:[{key}]");
 94
 95            _cache.Remove(key);
 96        }
 97
 98        public void Remove(string? host, int port, string? authenticationType)
 99        {
 100            if (host == null || authenticationType == null)
 101            {
 102                // These couldn't possibly have been inserted into
 103                // the cache because of the test in Add().
 104                return;
 105            }
 106
 107            if (port < 0)
 108            {
 109                return;
 110            }
 111
 112            if (_cacheForHosts == null)
 113            {
 114                if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "Short-circuiting because the dictionary i
 115                return;
 116            }
 117
 118            ++_version;
 119
 120            var key = new CredentialHostKey(host, port, authenticationType);
 121
 122            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Removing key:[{key}]");
 123
 124            _cacheForHosts.Remove(key);
 125        }
 126
 127        public NetworkCredential? GetCredential(Uri uriPrefix, string authType)
 128        {
 129            ArgumentNullException.ThrowIfNull(uriPrefix);
 130            ArgumentNullException.ThrowIfNull(authType);
 131
 132            if (_cache == null)
 133            {
 134                if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "CredentialCache::GetCredential short-circ
 135                return null;
 136            }
 137
 138            CredentialCacheHelper.TryGetCredential(_cache, uriPrefix, authType, out _ /*uri*/, out NetworkCredential? mo
 139
 140            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Returning {(mostSpecificMatch == null ? "nul
 141
 142            return mostSpecificMatch;
 143        }
 144
 145        public NetworkCredential? GetCredential(string host, int port, string authenticationType)
 146        {
 147            ArgumentException.ThrowIfNullOrEmpty(host);
 148            ArgumentNullException.ThrowIfNull(authenticationType);
 149            ArgumentOutOfRangeException.ThrowIfNegative(port);
 150
 151            if (_cacheForHosts == null)
 152            {
 153                if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "CredentialCache::GetCredential short-circ
 154                return null;
 155            }
 156
 157            var key = new CredentialHostKey(host, port, authenticationType);
 158
 159            NetworkCredential? match;
 160            _cacheForHosts.TryGetValue(key, out match);
 161
 162            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Returning {((match == null) ? "null" : "(" +
 163
 164            return match;
 165        }
 166
 167        public IEnumerator GetEnumerator() => CredentialEnumerator.Create(this);
 168
 169        public static ICredentials DefaultCredentials => SystemNetworkCredential.s_defaultCredential;
 170
 171        public static NetworkCredential DefaultNetworkCredentials => SystemNetworkCredential.s_defaultCredential;
 172
 173        private class CredentialEnumerator : IEnumerator
 174        {
 175            internal static CredentialEnumerator Create(CredentialCache cache)
 176            {
 177                Debug.Assert(cache != null);
 178
 179                if (cache._cache != null)
 180                {
 181                    return cache._cacheForHosts != null ?
 182                        new DoubleTableCredentialEnumerator(cache) :
 183                        new SingleTableCredentialEnumerator<CredentialCacheKey>(cache, cache._cache);
 184                }
 185                else
 186                {
 187                    return cache._cacheForHosts != null ?
 188                        new SingleTableCredentialEnumerator<CredentialHostKey>(cache, cache._cacheForHosts) :
 189                        new CredentialEnumerator(cache);
 190                }
 191            }
 192
 193            private readonly CredentialCache _cache;
 194            private readonly int _version;
 195            private bool _enumerating;
 196            private NetworkCredential? _current;
 197
 198            private CredentialEnumerator(CredentialCache cache)
 199            {
 200                Debug.Assert(cache != null);
 201
 202                _cache = cache;
 203                _version = cache._version;
 204            }
 205
 206            public object Current
 207            {
 208                get
 209                {
 210                    if (!_enumerating)
 211                    {
 212                        throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen);
 213                    }
 214                    if (_version != _cache._version)
 215                    {
 216                        throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
 217                    }
 218
 219                    return _current!;
 220                }
 221            }
 222
 223            public bool MoveNext()
 224            {
 225                if (_version != _cache._version)
 226                {
 227                    throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
 228                }
 229
 230                return _enumerating = MoveNext(out _current);
 231            }
 232
 233            protected virtual bool MoveNext(out NetworkCredential? current)
 234            {
 235                current = null;
 236                return false;
 237            }
 238
 239            public virtual void Reset()
 240            {
 241                _enumerating = false;
 242            }
 243
 244            private class SingleTableCredentialEnumerator<TKey> : CredentialEnumerator where TKey : notnull
 245            {
 246                private Dictionary<TKey, NetworkCredential>.ValueCollection.Enumerator _enumerator; // mutable struct fi
 247
 248                public SingleTableCredentialEnumerator(CredentialCache cache, Dictionary<TKey, NetworkCredential> table)
 249                {
 250                    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.
 255                    _enumerator = table.Values.GetEnumerator();
 256                }
 257
 258                protected override bool MoveNext(out NetworkCredential current) =>
 259                    DictionaryEnumeratorHelper.MoveNext(ref _enumerator, out current);
 260
 261                public override void Reset()
 262                {
 263                    DictionaryEnumeratorHelper.Reset(ref _enumerator);
 264                    base.Reset();
 265                }
 266            }
 267
 268            private sealed class DoubleTableCredentialEnumerator : SingleTableCredentialEnumerator<CredentialCacheKey>
 269            {
 270                private Dictionary<CredentialHostKey, NetworkCredential>.ValueCollection.Enumerator _enumerator; // muta
 271                private bool _onThisEnumerator;
 272
 273                public DoubleTableCredentialEnumerator(CredentialCache cache) : base(cache, cache._cache!)
 274                {
 275                    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.
 280                    _enumerator = cache._cacheForHosts.Values.GetEnumerator();
 281                }
 282
 283                protected override bool MoveNext(out NetworkCredential current)
 284                {
 285                    if (!_onThisEnumerator)
 286                    {
 287                        if (base.MoveNext(out current))
 288                        {
 289                            return true;
 290                        }
 291                        else
 292                        {
 293                            _onThisEnumerator = true;
 294                        }
 295                    }
 296
 297                    return DictionaryEnumeratorHelper.MoveNext(ref _enumerator, out current);
 298                }
 299
 300                public override void Reset()
 301                {
 302                    _onThisEnumerator = false;
 303                    DictionaryEnumeratorHelper.Reset(ref _enumerator);
 304                    base.Reset();
 305                }
 306            }
 307
 308            private static class DictionaryEnumeratorHelper
 309            {
 310                internal static bool MoveNext<TKey, TValue>(ref Dictionary<TKey, TValue>.ValueCollection.Enumerator enum
 311                {
 312                    bool result = enumerator.MoveNext();
 313                    current = enumerator.Current;
 314                    return result;
 315                }
 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
 319                {
 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.
 322                    try { enumerator.Reset(); } catch (InvalidOperationException) { }
 323                }
 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)
 0355        {
 0356            Debug.Assert(!string.IsNullOrEmpty(host));
 0357            Debug.Assert(port >= 0);
 0358            Debug.Assert(authenticationType != null);
 359
 0360            Host = host;
 0361            Port = port;
 0362            AuthenticationType = authenticationType;
 0363        }
 364
 365        public override int GetHashCode() =>
 0366            StringComparer.OrdinalIgnoreCase.GetHashCode(AuthenticationType) ^
 0367            StringComparer.OrdinalIgnoreCase.GetHashCode(Host) ^
 0368            Port.GetHashCode();
 369
 370        public bool Equals(CredentialHostKey other)
 0371        {
 0372            bool equals =
 0373                string.Equals(AuthenticationType, other.AuthenticationType, StringComparison.OrdinalIgnoreCase) &&
 0374                string.Equals(Host, other.Host, StringComparison.OrdinalIgnoreCase) &&
 0375                Port == other.Port;
 376
 0377            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Equals({this},{other}) returns {equals}");
 378
 0379            return equals;
 0380        }
 381
 382        public override bool Equals([NotNullWhen(true)] object? obj) =>
 0383            obj is CredentialHostKey && Equals((CredentialHostKey)obj);
 384
 385        public override string ToString() =>
 0386            string.Create(CultureInfo.InvariantCulture, $"{Host}:{Port}:{AuthenticationType}");
 387    }
 388}
 389