< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Security.IdentityVerifier
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/IdentityVerifier.cs
Line coverage
3%
Covered lines: 4
Uncovered lines: 114
Coverable lines: 118
Total lines: 348
Line coverage: 3.3%
Branch coverage
0%
Covered branches: 0
Total branches: 86
Branch coverage: 0%
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/Security/IdentityVerifier.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.Generic;
 6using System.Collections.ObjectModel;
 7using System.Globalization;
 8using System.Security.Principal;
 9using CoreWCF.Channels;
 10using CoreWCF.IdentityModel.Claims;
 11using CoreWCF.IdentityModel.Policy;
 12using CoreWCF.Runtime.Diagnostics;
 13using CoreWCF.Security.Tokens;
 14
 15namespace CoreWCF.Security
 16{
 17    public abstract class IdentityVerifier
 18    {
 319        protected IdentityVerifier()
 20        {
 21            // empty
 322        }
 23
 24        public static IdentityVerifier CreateDefault()
 25        {
 1726            return DefaultIdentityVerifier.Instance;
 27        }
 28
 29        internal bool CheckAccess(EndpointAddress reference, Message message)
 30        {
 031            if (reference == null)
 32            {
 033                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(reference));
 34            }
 35
 036            if (message == null)
 37            {
 038                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(message));
 39            }
 40
 041            if (!TryGetIdentity(reference, out EndpointIdentity identity))
 42            {
 043                return false;
 44            }
 45
 46            //SecurityMessageProperty securityContextProperty = null;
 47            //if (message.Properties != null)
 48            //    securityContextProperty = message.Properties.Security;
 49
 50            //if (securityContextProperty == null || securityContextProperty.ServiceSecurityContext == null)
 51            //    return false;
 52
 53            //return this.CheckAccess(identity, securityContextProperty.ServiceSecurityContext.AuthorizationContext);
 54            return false;
 55        }
 56
 57        public abstract bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext);
 58
 59        public abstract bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity);
 60
 61        private static void AdjustAddress(ref EndpointAddress reference, Uri via)
 62        {
 63            // if we don't have an identity and we have differing Uris, we should use the Via
 064            if (reference.Identity == null && reference.Uri != via)
 65            {
 066                reference = new EndpointAddress(via);
 67            }
 068        }
 69
 70        internal bool TryGetIdentity(EndpointAddress reference, Uri via, out EndpointIdentity identity)
 71        {
 072            AdjustAddress(ref reference, via);
 073            return TryGetIdentity(reference, out identity);
 74        }
 75
 76        internal void EnsureIncomingIdentity(EndpointAddress serviceReference, AuthorizationContext authorizationContext
 77        {
 078            EnsureIdentity(serviceReference, authorizationContext, SR.IdentityCheckFailedForIncomingMessage);
 079        }
 80
 81        internal void EnsureOutgoingIdentity(EndpointAddress serviceReference, Uri via, AuthorizationContext authorizati
 82        {
 083            AdjustAddress(ref serviceReference, via);
 084            EnsureIdentity(serviceReference, authorizationContext, SR.IdentityCheckFailedForOutgoingMessage);
 085        }
 86
 87        internal void EnsureOutgoingIdentity(EndpointAddress serviceReference, ReadOnlyCollection<IAuthorizationPolicy> 
 88        {
 089            if (authorizationPolicies == null)
 90            {
 091                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(authorizationPolicies));
 92            }
 093            AuthorizationContext ac = AuthorizationContext.CreateDefaultAuthorizationContext(authorizationPolicies);
 094            EnsureIdentity(serviceReference, ac, SR.IdentityCheckFailedForOutgoingMessage);
 095        }
 96
 97        private void EnsureIdentity(EndpointAddress serviceReference, AuthorizationContext authorizationContext, string 
 98        {
 099            if (authorizationContext == null)
 100            {
 0101                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(authorizationContext));
 102            }
 0103            if (!TryGetIdentity(serviceReference, out EndpointIdentity identity))
 104            {
 105                //SecurityTraceRecordHelper.TraceIdentityVerificationFailure(identity, authorizationContext, this.GetTyp
 0106                throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.Format(error
 107            }
 108            else
 109            {
 0110                if (!CheckAccess(identity, authorizationContext))
 111                {
 112                    // CheckAccess performs a Trace on failure, no need to do it twice
 0113                    Exception e = CreateIdentityCheckException(identity, authorizationContext, errorString, serviceRefer
 0114                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(e);
 115                }
 116            }
 0117        }
 118
 119        private Exception CreateIdentityCheckException(EndpointIdentity identity, AuthorizationContext authorizationCont
 120        {
 121            Exception result;
 122
 0123            if (identity.IdentityClaim != null
 0124                && identity.IdentityClaim.ClaimType == ClaimTypes.Dns
 0125                && identity.IdentityClaim.Right == Rights.PossessProperty
 0126                && identity.IdentityClaim.Resource is string)
 127            {
 0128                string expectedDnsName = (string)identity.IdentityClaim.Resource;
 0129                string actualDnsName = null;
 0130                for (int i = 0; i < authorizationContext.ClaimSets.Count; ++i)
 131                {
 0132                    ClaimSet claimSet = authorizationContext.ClaimSets[i];
 0133                    foreach (Claim claim in claimSet.FindClaims(ClaimTypes.Dns, Rights.PossessProperty))
 134                    {
 0135                        if (claim.Resource is string)
 136                        {
 0137                            actualDnsName = (string)claim.Resource;
 0138                            break;
 139                        }
 140                    }
 0141                    if (actualDnsName != null)
 142                    {
 143                        break;
 144                    }
 145                }
 0146                if (SR.IdentityCheckFailedForIncomingMessage.Equals(errorString))
 147                {
 0148                    if (actualDnsName == null)
 149                    {
 0150                        result = new MessageSecurityException(SR.Format(SR.DnsIdentityCheckFailedForIncomingMessageLackO
 151                    }
 152                    else
 153                    {
 0154                        result = new MessageSecurityException(SR.Format(SR.DnsIdentityCheckFailedForIncomingMessage, exp
 155                    }
 156                }
 0157                else if (SR.IdentityCheckFailedForOutgoingMessage.Equals(errorString))
 158                {
 0159                    if (actualDnsName == null)
 160                    {
 0161                        result = new MessageSecurityException(SR.Format(SR.DnsIdentityCheckFailedForOutgoingMessageLackO
 162                    }
 163                    else
 164                    {
 0165                        result = new MessageSecurityException(SR.Format(SR.DnsIdentityCheckFailedForOutgoingMessage, exp
 166                    }
 167                }
 168                else
 169                {
 0170                    result = new MessageSecurityException(SR.Format(errorString, identity, serviceReference));
 171                }
 172            }
 173            else
 174            {
 0175                result = new MessageSecurityException(SR.Format(errorString, identity, serviceReference));
 176            }
 177
 0178            return result;
 179        }
 180
 181        private class DefaultIdentityVerifier : IdentityVerifier
 182        {
 20183            public static DefaultIdentityVerifier Instance { get; } = new DefaultIdentityVerifier();
 184
 185            public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity)
 186            {
 0187                if (reference == null)
 188                {
 0189                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(reference));
 190                }
 191
 0192                identity = reference.Identity;
 193
 0194                if (identity == null)
 195                {
 0196                    identity = TryCreateDnsIdentity(reference);
 197                }
 198
 0199                if (identity == null)
 200                {
 0201                    SecurityTraceRecordHelper.TraceIdentityDeterminationFailure(reference, typeof(DefaultIdentityVerifie
 0202                    return false;
 203                }
 204                else
 205                {
 0206                    SecurityTraceRecordHelper.TraceIdentityDeterminationSuccess(reference, identity, typeof(DefaultIdent
 0207                    return true;
 208                }
 209            }
 210
 211            private EndpointIdentity TryCreateDnsIdentity(EndpointAddress reference)
 212            {
 0213                Uri toAddress = reference.Uri;
 214
 0215                if (!toAddress.IsAbsoluteUri)
 216                {
 0217                    return null;
 218                }
 219
 0220                return EndpointIdentity.CreateDnsIdentity(toAddress.DnsSafeHost);
 221            }
 222
 223            private SecurityIdentifier GetSecurityIdentifier(Claim claim)
 224            {
 225                // if the incoming claim is a SID and the EndpointIdentity is UPN/SPN/DNS, try to find the SID correspon
 226                // the UPN/SPN/DNS (transactions case)
 0227                if (claim.Resource is WindowsIdentity)
 228                {
 0229                    return ((WindowsIdentity)claim.Resource).User;
 230                }
 0231                else if (claim.Resource is WindowsSidIdentity)
 232                {
 0233                    return ((WindowsSidIdentity)claim.Resource).SecurityIdentifier;
 234                }
 235
 0236                return claim.Resource as SecurityIdentifier;
 237            }
 238
 239            private Claim CheckDnsEquivalence(ClaimSet claimSet, string expectedSpn)
 240            {
 241                // host/<machine-name> satisfies the DNS identity claim
 0242                IEnumerable<Claim> claims = claimSet.FindClaims(ClaimTypes.Spn, Rights.PossessProperty);
 0243                foreach (Claim claim in claims)
 244                {
 0245                    if (expectedSpn.Equals((string)claim.Resource, StringComparison.OrdinalIgnoreCase))
 246                    {
 0247                        return claim;
 248                    }
 249                }
 0250                return null;
 0251            }
 252
 253            private Claim CheckSidEquivalence(SecurityIdentifier identitySid, ClaimSet claimSet)
 254            {
 0255                foreach (Claim claim in claimSet)
 256                {
 0257                    SecurityIdentifier sid = GetSecurityIdentifier(claim);
 0258                    if (sid != null)
 259                    {
 0260                        if (identitySid.Equals(sid))
 261                        {
 0262                            return claim;
 263                        }
 264                    }
 265                }
 0266                return null;
 0267            }
 268
 269            public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext)
 270            {
 271                //EventTraceActivity eventTraceActivity = null;
 272
 0273                if (identity == null)
 274                {
 0275                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(identity));
 276                }
 277
 0278                if (authContext == null)
 279                {
 0280                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(authContext));
 281                }
 282
 283
 284                //if (FxTrace.Trace.IsEnd2EndActivityTracingEnabled)
 285                //{
 286                //    eventTraceActivity = EventTraceActivityHelper.TryExtractActivity((OperationContext.Current != null
 287                //}
 288
 0289                for (int i = 0; i < authContext.ClaimSets.Count; ++i)
 290                {
 0291                    ClaimSet claimSet = authContext.ClaimSets[i];
 0292                    if (claimSet.ContainsClaim(identity.IdentityClaim))
 293                    {
 294                        //SecurityTraceRecordHelper.TraceIdentityVerificationSuccess(eventTraceActivity, identity, ident
 0295                        return true;
 296                    }
 297
 298                    // try Claim equivalence
 0299                    string expectedSpn = null;
 0300                    if (ClaimTypes.Dns.Equals(identity.IdentityClaim.ClaimType))
 301                    {
 0302                        expectedSpn = string.Format(CultureInfo.InvariantCulture, "host/{0}", (string)identity.IdentityC
 0303                        Claim claim = CheckDnsEquivalence(claimSet, expectedSpn);
 0304                        if (claim != null)
 305                        {
 306                            //SecurityTraceRecordHelper.TraceIdentityVerificationSuccess(eventTraceActivity, identity, c
 0307                            return true;
 308                        }
 309                    }
 310                    // Allow a Sid claim to support UPN, and SPN identities
 0311                    SecurityIdentifier identitySid = null;
 0312                    if (ClaimTypes.Sid.Equals(identity.IdentityClaim.ClaimType))
 313                    {
 0314                        identitySid = GetSecurityIdentifier(identity.IdentityClaim);
 315                    }
 0316                    else if (ClaimTypes.Upn.Equals(identity.IdentityClaim.ClaimType))
 317                    {
 0318                        identitySid = ((UpnEndpointIdentity)identity).GetUpnSid();
 319                    }
 0320                    else if (ClaimTypes.Spn.Equals(identity.IdentityClaim.ClaimType))
 321                    {
 0322                        identitySid = ((SpnEndpointIdentity)identity).GetSpnSid();
 323                    }
 0324                    else if (ClaimTypes.Dns.Equals(identity.IdentityClaim.ClaimType))
 325                    {
 0326                        identitySid = new SpnEndpointIdentity(expectedSpn).GetSpnSid();
 327                    }
 0328                    if (identitySid != null)
 329                    {
 0330                        Claim claim = CheckSidEquivalence(identitySid, claimSet);
 0331                        if (claim != null)
 332                        {
 333                            //SecurityTraceRecordHelper.TraceIdentityVerificationSuccess(eventTraceActivity, identity, c
 0334                            return true;
 335                        }
 336                    }
 337                }
 0338                SecurityTraceRecordHelper.TraceIdentityVerificationFailure(identity, authContext, GetType());
 339                //if (TD.SecurityIdentityVerificationFailureIsEnabled())
 340                //{
 341                //    TD.SecurityIdentityVerificationFailure(eventTraceActivity);
 342                //}
 343
 0344                return false;
 345            }
 346        }
 347    }
 348}