< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.IdentityModel.Claims.ClaimComparer
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/IdentityModel/Claims/ClaimComparer.cs
Line coverage
32%
Covered lines: 34
Uncovered lines: 71
Coverable lines: 105
Total lines: 412
Line coverage: 32.3%
Branch coverage
25%
Covered branches: 25
Total branches: 98
Branch coverage: 25.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/IdentityModel/Claims/ClaimComparer.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.Security.Cryptography;
 8using System.Security.Cryptography.X509Certificates;
 9
 10namespace CoreWCF.IdentityModel.Claims
 11{
 12    internal class ClaimComparer : IEqualityComparer<Claim>
 13    {
 14        private static IEqualityComparer<Claim> s_defaultComparer;
 15        private static IEqualityComparer<Claim> s_hashComparer;
 16        private static IEqualityComparer<Claim> s_dnsComparer;
 17        private static IEqualityComparer<Claim> s_rsaComparer;
 18        private static IEqualityComparer<Claim> s_thumbprintComparer;
 19        //private static IEqualityComparer<Claim> upnComparer;
 20        private static IEqualityComparer<Claim> s_x500DistinguishedNameComparer;
 21
 22        private readonly IEqualityComparer _resourceComparer;
 23
 624        private ClaimComparer(IEqualityComparer resourceComparer)
 25        {
 626            _resourceComparer = resourceComparer;
 627        }
 28
 29        public static IEqualityComparer<Claim> GetComparer(string claimType)
 30        {
 631            if (claimType == null)
 32            {
 033                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(claimType));
 34            }
 35
 636            if (claimType == ClaimTypes.Dns)
 37            {
 038                return Dns;
 39            }
 40
 641            if (claimType == ClaimTypes.Hash)
 42            {
 043                return Hash;
 44            }
 45
 646            if (claimType == ClaimTypes.Rsa)
 47            {
 048                return Rsa;
 49            }
 50
 651            if (claimType == ClaimTypes.Thumbprint)
 52            {
 053                return Thumbprint;
 54            }
 55
 656            if (claimType == ClaimTypes.Upn)
 57            {
 058                return Upn;
 59            }
 60
 661            if (claimType == ClaimTypes.X500DistinguishedName)
 62            {
 063                return X500DistinguishedName;
 64            }
 65
 666            return Default;
 67        }
 68
 69        public static IEqualityComparer<Claim> Default
 70        {
 71            get
 72            {
 673                if (s_defaultComparer == null)
 74                {
 175                    s_defaultComparer = new ClaimComparer(new ObjectComparer());
 76                }
 77
 678                return s_defaultComparer;
 79            }
 80        }
 81
 82        public static IEqualityComparer<Claim> Dns
 83        {
 84            get
 85            {
 786                if (s_dnsComparer == null)
 87                {
 388                    s_dnsComparer = new ClaimComparer(StringComparer.OrdinalIgnoreCase);
 89                }
 90
 791                return s_dnsComparer;
 92            }
 93        }
 94
 95        public static IEqualityComparer<Claim> Hash
 96        {
 97            get
 98            {
 099                if (s_hashComparer == null)
 100                {
 0101                    s_hashComparer = new ClaimComparer(new BinaryObjectComparer());
 102                }
 103
 0104                return s_hashComparer;
 105            }
 106        }
 107
 108        public static IEqualityComparer<Claim> Rsa
 109        {
 110            get
 111            {
 2112                if (s_rsaComparer == null)
 113                {
 1114                    s_rsaComparer = new ClaimComparer(new RsaObjectComparer());
 115                }
 116
 2117                return s_rsaComparer;
 118            }
 119        }
 120
 121        public static IEqualityComparer<Claim> Thumbprint
 122        {
 123            get
 124            {
 0125                if (s_thumbprintComparer == null)
 126                {
 0127                    s_thumbprintComparer = new ClaimComparer(new BinaryObjectComparer());
 128                }
 129
 0130                return s_thumbprintComparer;
 131            }
 132        }
 133
 134        public static IEqualityComparer<Claim> Upn
 135        {
 136            get
 137            {
 0138                return Default;
 139                //The UpnComparer behavior in Core is different than .NET Framework.
 140                //In .NET Framework the UpnComparer has a dependency on NTAccount,
 141                // which isn't available on Core.
 142            }
 143        }
 144
 145        public static IEqualityComparer<Claim> X500DistinguishedName
 146        {
 147            get
 148            {
 2149                if (s_x500DistinguishedNameComparer == null)
 150                {
 1151                    s_x500DistinguishedNameComparer = new ClaimComparer(new X500DistinguishedNameObjectComparer());
 152                }
 153
 2154                return s_x500DistinguishedNameComparer;
 155            }
 156        }
 157
 158        // we still need to review how the default equals works, this is not how Doug envisioned it.
 159        public bool Equals(Claim claim1, Claim claim2)
 160        {
 12161            if (ReferenceEquals(claim1, claim2))
 162            {
 4163                return true;
 164            }
 165
 8166            if (claim1 == null || claim2 == null)
 167            {
 0168                return false;
 169            }
 170
 8171            if (claim1.ClaimType != claim2.ClaimType || claim1.Right != claim2.Right)
 172            {
 0173                return false;
 174            }
 175
 8176            return _resourceComparer.Equals(claim1.Resource, claim2.Resource);
 177        }
 178
 179        public int GetHashCode(Claim claim)
 180        {
 0181            if (claim == null)
 182            {
 0183                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(claim));
 184            }
 185
 0186            return claim.ClaimType.GetHashCode() ^ claim.Right.GetHashCode()
 0187                ^ ((claim.Resource == null) ? 0 : _resourceComparer.GetHashCode(claim.Resource));
 188        }
 189
 190        private class ObjectComparer : IEqualityComparer
 191        {
 192            bool IEqualityComparer.Equals(object obj1, object obj2)
 193            {
 8194                if (obj1 == null && obj2 == null)
 195                {
 0196                    return true;
 197                }
 198
 8199                if (obj1 == null || obj2 == null)
 200                {
 0201                    return false;
 202                }
 203
 8204                return obj1.Equals(obj2);
 205            }
 206
 207            int IEqualityComparer.GetHashCode(object obj)
 208            {
 0209                if (obj == null)
 210                {
 0211                    return 0;
 212                }
 213
 0214                return obj.GetHashCode();
 215            }
 216        }
 217
 218        private class BinaryObjectComparer : IEqualityComparer
 219        {
 220            bool IEqualityComparer.Equals(object obj1, object obj2)
 221            {
 0222                if (ReferenceEquals(obj1, obj2))
 223                {
 0224                    return true;
 225                }
 0226                if (!(obj1 is byte[] bytes1) || !(obj2 is byte[] bytes2))
 227                {
 0228                    return false;
 229                }
 230
 0231                if (bytes1.Length != bytes2.Length)
 232                {
 0233                    return false;
 234                }
 235
 0236                for (int i = 0; i < bytes1.Length; ++i)
 237                {
 0238                    if (bytes1[i] != bytes2[i])
 239                    {
 0240                        return false;
 241                    }
 242                }
 243
 0244                return true;
 245            }
 246
 247            int IEqualityComparer.GetHashCode(object obj)
 248            {
 0249                if (!(obj is byte[] bytes))
 250                {
 0251                    return 0;
 252                }
 253
 0254                int hashCode = 0;
 0255                for (int i = 0; i < bytes.Length && i < 4; ++i)
 256                {
 0257                    hashCode = (hashCode << 8) | bytes[i];
 258                }
 259
 0260                return hashCode ^ bytes.Length;
 261            }
 262        }
 263
 264        private class RsaObjectComparer : IEqualityComparer
 265        {
 266            bool IEqualityComparer.Equals(object obj1, object obj2)
 267            {
 0268                if (ReferenceEquals(obj1, obj2))
 269                {
 0270                    return true;
 271                }
 0272                if (!(obj1 is RSA rsa1) || !(obj2 is RSA rsa2))
 273                {
 0274                    return false;
 275                }
 276
 0277                RSAParameters parm1 = rsa1.ExportParameters(false);
 0278                RSAParameters parm2 = rsa2.ExportParameters(false);
 279
 0280                if (parm1.Modulus.Length != parm2.Modulus.Length ||
 0281                    parm1.Exponent.Length != parm2.Exponent.Length)
 282                {
 0283                    return false;
 284                }
 285
 0286                for (int i = 0; i < parm1.Modulus.Length; ++i)
 287                {
 0288                    if (parm1.Modulus[i] != parm2.Modulus[i])
 289                    {
 0290                        return false;
 291                    }
 292                }
 293
 0294                for (int i = 0; i < parm1.Exponent.Length; ++i)
 295                {
 0296                    if (parm1.Exponent[i] != parm2.Exponent[i])
 297                    {
 0298                        return false;
 299                    }
 300                }
 301
 0302                return true;
 303            }
 304
 305            int IEqualityComparer.GetHashCode(object obj)
 306            {
 0307                if (!(obj is RSA rsa))
 308                {
 0309                    return 0;
 310                }
 311
 0312                RSAParameters parm = rsa.ExportParameters(false);
 0313                return parm.Modulus.Length ^ parm.Exponent.Length;
 314            }
 315        }
 316
 317        private class X500DistinguishedNameObjectComparer : IEqualityComparer
 318        {
 319            private readonly IEqualityComparer _binaryComparer;
 1320            public X500DistinguishedNameObjectComparer()
 321            {
 1322                _binaryComparer = new BinaryObjectComparer();
 1323            }
 324
 325            bool IEqualityComparer.Equals(object obj1, object obj2)
 326            {
 0327                if (ReferenceEquals(obj1, obj2))
 328                {
 0329                    return true;
 330                }
 0331                if (!(obj1 is X500DistinguishedName dn1) || !(obj2 is X500DistinguishedName dn2))
 332                {
 0333                    return false;
 334                }
 335
 336                // 1) Hopefully cover most cases (perf reason).
 0337                if (StringComparer.Ordinal.Equals(dn1.Name, dn2.Name))
 338                {
 0339                    return true;
 340                }
 341
 342                // 2) Raw byte compare.  Note: we assume the rawbyte is in the same order
 343                // (default = X500DistinguishedNameFlags.Reversed).
 0344                return _binaryComparer.Equals(dn1.RawData, dn2.RawData);
 345            }
 346
 347            int IEqualityComparer.GetHashCode(object obj)
 348            {
 0349                if (!(obj is X500DistinguishedName dn))
 350                {
 0351                    return 0;
 352                }
 353
 0354                return _binaryComparer.GetHashCode(dn.RawData);
 355            }
 356        }
 357
 358        //class UpnObjectComparer : IEqualityComparer
 359        //{
 360        //    bool IEqualityComparer.Equals(object obj1, object obj2)
 361        //    {
 362        //        if (StringComparer.OrdinalIgnoreCase.Equals(obj1, obj2))
 363        //            return true;
 364
 365        //        string upn1 = obj1 as string;
 366        //        string upn2 = obj2 as string;
 367        //        if (upn1 == null || upn2 == null)
 368        //            return false;
 369
 370        //        SecurityIdentifier sid1;
 371        //        if (!TryLookupSidFromName(upn1, out sid1))
 372        //            return false;
 373
 374        //        // Normalize to sid
 375        //        SecurityIdentifier sid2;
 376        //        if (!TryLookupSidFromName(upn2, out sid2))
 377        //            return false;
 378
 379        //        return sid1 == sid2;
 380        //    }
 381
 382        //    int IEqualityComparer.GetHashCode(object obj)
 383        //    {
 384        //        string upn = obj as string;
 385        //        if (upn == null)
 386        //            return 0;
 387
 388        //        // Normalize to sid
 389        //        SecurityIdentifier sid;
 390        //        if (TryLookupSidFromName(upn, out sid))
 391        //            return sid.GetHashCode();
 392
 393        //        return StringComparer.OrdinalIgnoreCase.GetHashCode(upn);
 394        //    }
 395
 396        //    bool TryLookupSidFromName(string upn, out SecurityIdentifier sid)
 397        //    {
 398        //        sid = null;
 399        //        try
 400        //        {
 401        //            NTAccount acct = new NTAccount(upn);
 402        //            sid = acct.Translate(typeof(SecurityIdentifier)) as SecurityIdentifier;
 403        //        }
 404        //        catch (IdentityNotMappedException e)
 405        //        {
 406        //            DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 407        //        }
 408        //        return sid != null;
 409        //    }
 410        //}
 411    }
 412}