< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Security.IdentityModelServiceAuthorizationManager
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/IdentityModelServiceAuthorizationManager.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 136
Coverable lines: 136
Total lines: 591
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 92
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/IdentityModelServiceAuthorizationManager.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.Linq;
 9using System.Security.Claims;
 10using System.Security.Principal;
 11using System.Threading.Tasks;
 12using System.Xml;
 13using CoreWCF.Description;
 14using CoreWCF.IdentityModel;
 15using CoreWCF.IdentityModel.Claims;
 16using CoreWCF.IdentityModel.Policy;
 17using CoreWCF.IdentityModel.Tokens;
 18using CoreWCF.Security.Claims;
 19using SysAuthorizationContext = CoreWCF.IdentityModel.Policy.AuthorizationContext;
 20
 21namespace CoreWCF.Security
 22{
 23    /// <summary>
 24    /// Custom ServiceAuthorizationManager implementation. This class substitues the WCF
 25    /// generated IAuthorizationPolicies with
 26    /// <see cref="CoreWCF.IdentityModel.Tokens.AuthorizationPolicy"/>. These
 27    /// policies do not participate in the EvaluationContext and hence will render an
 28    /// empty WCF AuthorizationConext. Once this AuthorizationManager is substitued to
 29    /// a ServiceHost, only <see cref="System.Security.Claims.ClaimsPrincipal"/>
 30    /// will be available for Authorization decisions.
 31    /// </summary>
 32    internal class IdentityModelServiceAuthorizationManager : ServiceAuthorizationManager
 33    {
 34        /// <summary>
 35        /// Authorization policy for anonymous authentication.
 36        /// </summary>
 037        protected static readonly ReadOnlyCollection<IAuthorizationPolicy> AnonymousAuthorizationPolicy
 038            = new ReadOnlyCollection<IAuthorizationPolicy>(
 039                new List<IAuthorizationPolicy>() { new AuthorizationPolicy(new ClaimsIdentity()) });
 40
 41        /// <summary>
 42        /// Override of the base class method. Substitues WCF IAuthorizationPolicy with
 43        /// <see cref="CoreWCF.IdentityModel.Tokens.AuthorizationPolicy"/>.
 44        /// </summary>
 45        /// <param name="operationContext">Current OperationContext that contains all the IAuthorizationPolicies.</param
 46        /// <returns>Read-Only collection of <see cref="IAuthorizationPolicy"/> </returns>
 47        protected override ReadOnlyCollection<IAuthorizationPolicy> GetAuthorizationPolicies(OperationContext operationC
 48        {
 49            //
 50            // Make sure we always return at least one claims identity, if there are no auth policies
 51            // that contain any identities, then return an anonymous identity wrapped in an authorization policy.
 52            //
 53            // If we do not, then Thread.CurrentPrincipal may end up being null inside service operations after the
 54            // authorization polices are evaluated since ServiceCredentials.ConfigureServiceHost will
 55            // turn the PrincipalPermissionMode knob to Custom.
 56            //
 57
 058            ReadOnlyCollection<IAuthorizationPolicy> baseAuthorizationPolicies = base.GetAuthorizationPolicies(operation
 059            if (baseAuthorizationPolicies == null)
 60            {
 061                return AnonymousAuthorizationPolicy;
 62            }
 63            else
 64            {
 065                ServiceCredentials sc = GetServiceCredentials();
 066                AuthorizationPolicy transformedPolicy = TransformAuthorizationPolicies(baseAuthorizationPolicies,
 067                                                                                        sc.IdentityConfiguration.Securit
 068                                                                                        true);
 069                if (transformedPolicy == null || transformedPolicy.IdentityCollection.Count == 0)
 70                {
 071                    return AnonymousAuthorizationPolicy;
 72                }
 073                return (new List<IAuthorizationPolicy>() { transformedPolicy }).AsReadOnly();
 74            }
 75        }
 76
 77        internal static AuthorizationPolicy TransformAuthorizationPolicies(
 78            ReadOnlyCollection<IAuthorizationPolicy> baseAuthorizationPolicies,
 79            SecurityTokenHandlerCollection securityTokenHandlerCollection,
 80            bool includeTransportTokens)
 81        {
 082            List<ClaimsIdentity> identities = new List<ClaimsIdentity>();
 083            List<IAuthorizationPolicy> uncheckedAuthorizationPolicies = new List<IAuthorizationPolicy>();
 84
 85            //
 86            // STEP 1: Filter out the IAuthorizationPolicy that WCF generated. These
 87            //         are generated as IDFx does not have a proper SecurityTokenHandler
 88            //         to handle these. For example, SSPI at message layer and all token
 89            //         types at the Transport layer.
 90            //
 091            foreach (IAuthorizationPolicy authPolicy in baseAuthorizationPolicies)
 92            {
 093                if ((authPolicy is SctAuthorizationPolicy) ||
 094                    (authPolicy is EndpointAuthorizationPolicy))
 95                {
 96                    //
 97                    // We ignore the SctAuthorizationPolicy if any found as they were created
 98                    // as wrapper policies to hold the primary identity claim during a token renewal path.
 99                    // WCF would otherwise fault thinking the token issuance and renewal identities are
 100                    // different. This policy should be treated as a dummy policy and thereby should not be transformed.
 101                    //
 102                    // We ignore EndpointAuthorizationPolicy as well. This policy is used only to carry
 103                    // the endpoint Identity and there is no useful claims that this policy contributes.
 104                    //
 105                    continue;
 106                }
 107
 108
 0109                if (authPolicy is AuthorizationPolicy idfxAuthPolicy)
 110                {
 111                    // Identities obtained from the Tokens in the message layer would
 0112                    identities.AddRange(idfxAuthPolicy.IdentityCollection);
 113                }
 114                else
 115                {
 0116                    uncheckedAuthorizationPolicies.Add(authPolicy);
 117                }
 118            }
 119
 120            //
 121            // STEP 2: Generate IDFx claims from the transport token
 122            //
 0123            if (includeTransportTokens && (OperationContext.Current != null) &&
 0124                (OperationContext.Current.IncomingMessageProperties != null) &&
 0125                (OperationContext.Current.IncomingMessageProperties.Security != null) &&
 0126                (OperationContext.Current.IncomingMessageProperties.Security.TransportToken != null))
 127            {
 0128                SecurityToken transportToken =
 0129                    OperationContext.Current.IncomingMessageProperties.Security.TransportToken.SecurityToken;
 130
 0131                ReadOnlyCollection<IAuthorizationPolicy> policyCollection =
 0132                    OperationContext.Current.IncomingMessageProperties.Security.TransportToken.SecurityTokenPolicies;
 0133                bool isWcfAuthPolicy = true;
 134
 0135                foreach (IAuthorizationPolicy policy in policyCollection)
 136                {
 137                    //
 138                    // Iterate over each of the policies in the policyCollection to make sure
 139                    // we don't have an idfx policy, if we do we will not consider this as
 140                    // a wcf auth policy: Such a case will be hit for the SslStreamSecurityBinding over net tcp
 141                    //
 142
 0143                    if (policy is AuthorizationPolicy)
 144                    {
 0145                        isWcfAuthPolicy = false;
 0146                        break;
 147                    }
 148                }
 149
 0150                if (isWcfAuthPolicy)
 151                {
 0152                    ReadOnlyCollection<ClaimsIdentity> tranportTokenIdentities = GetTransportTokenIdentities(transportTo
 0153                    identities.AddRange(tranportTokenIdentities);
 154
 155                    //
 156                    // NOTE: In the below code, we are trying to identify the IAuthorizationPolicy that WCF
 157                    // created for the Transport token and eliminate it. This assumes that any client Security
 158                    // Token that came in the Security header would have been validated by the SecurityTokenHandler
 159                    // and hence would have created a IDFx AuthorizationPolicy.
 160                    // For example, if X.509 Certificate was used to authenticate the client at the transport layer
 161                    // and then again at the Message security layer we depend on our TokenHandlers to have been in
 162                    // place to validate the X.509 Certificate at the message layer. This would clearly distinguish
 163                    // which policy was created for the Transport token by WCF.
 164                    //
 0165                    EliminateTransportTokenPolicy(transportToken, tranportTokenIdentities, uncheckedAuthorizationPolicie
 166                }
 167            }
 168
 169            //
 170            // STEP 3: Process any uncheckedAuthorizationPolicies here. Convert these to IDFx
 171            //         Claims.
 172            //
 0173            if (uncheckedAuthorizationPolicies.Count > 0)
 174            {
 0175                identities.AddRange(ConvertToIDFxIdentities(uncheckedAuthorizationPolicies, securityTokenHandlerCollecti
 176            }
 177
 178            //
 179            // STEP 4: Create an AuthorizationPolicy with all the ClaimsIdentities.
 180            //
 0181            AuthorizationPolicy idfxAuthorizationPolicy = null;
 0182            if (identities.Count == 0)
 183            {
 184                //
 185                // No IDFx ClaimsIdentity was found. Return AnonymousIdentity.
 186                //
 0187                idfxAuthorizationPolicy = new AuthorizationPolicy(new ClaimsIdentity());
 188            }
 189            else
 190            {
 0191                idfxAuthorizationPolicy = new AuthorizationPolicy(identities.AsReadOnly());
 192            }
 193
 0194            return idfxAuthorizationPolicy;
 195        }
 196
 197        /// <summary>
 198        /// Creates ClaimsIdentityCollection for the given Transport SecurityToken.
 199        /// </summary>
 200        /// <param name="transportToken">Client SecurityToken provided at the Transport layer.</param>
 201        /// <returns>ClaimsIdentityCollection built from the Transport SecurityToken</returns>
 202        private static ReadOnlyCollection<ClaimsIdentity> GetTransportTokenIdentities(SecurityToken transportToken)
 203        {
 0204            if (transportToken == null)
 205            {
 0206                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(transportToken));
 207            }
 208
 0209            ServiceCredentials serviceCreds = GetServiceCredentials();
 210
 0211            List<ClaimsIdentity> transportTokenIdentityCollection = new List<ClaimsIdentity>();
 212
 213            //////////////////////////////////////////////////////////////////////////////////////////
 214            //
 215            // There are 5 well-known Client Authentication types at the transport layer. Each of these will
 216            // result either in a WindowsSecurityToken, X509SecurityToken or UserNameSecurityToken.
 217            // All other type of credentials (like OAuth token) result other token that will be passed trough regular va
 218            //
 219            //      ClientCredential Type     ||        Transport Token Type
 220            // -------------------------------------------------------------------
 221            //          Basic                 ->        UserNameSecurityToken (In Self-hosted case)
 222            //          Basic                 ->        WindowsSecurityToken (In Web-Hosted case)
 223            //          NTLM                  ->        WindowsSecurityToken
 224            //          Negotiate             ->        WindowsSecurityToken
 225            //          Windows               ->        WindowsSecurityToken
 226            //          Certificate           ->        X509SecurityToken
 227            //
 228            //////////////////////////////////////////////////////////////////////////////////////////
 229
 0230            if (transportToken is WindowsSecurityToken windowsSecurityToken)
 231            {
 0232                WindowsIdentity claimsIdentity = new WindowsIdentity(windowsSecurityToken.WindowsIdentity.Token,
 0233                    AuthenticationTypes.Windows);
 0234                AddAuthenticationMethod(claimsIdentity, AuthenticationMethods.Windows);
 0235                AddAuthenticationInstantClaim(claimsIdentity, XmlConvert.ToString(DateTime.UtcNow, DateTimeFormats.Gener
 236
 237                // Just reflect on the wrapped WindowsIdentity and build the WindowsClaimsIdentity class.
 0238                transportTokenIdentityCollection.Add(claimsIdentity);
 239            }
 240            else
 241            {
 242                // WCF does not call our SecurityTokenHandlers for the Transport token. So run the token through
 243                // the SecurityTokenHandler and generate claims for this token.
 0244                transportTokenIdentityCollection.AddRange(serviceCreds.IdentityConfiguration.SecurityTokenHandlers.Valid
 245            }
 246
 0247            return transportTokenIdentityCollection.AsReadOnly();
 248        }
 249
 250        /// <summary>
 251        /// Given a collection of IAuthorizationPolicies this method will eliminate the IAuthorizationPolicy
 252        /// that was created for the given transport Security Token. The method modifies the given collection
 253        /// of IAuthorizationPolicy.
 254        /// </summary>
 255        /// <param name="transportToken">Client's Security Token provided at the transport layer.</param>
 256        /// <param name="tranportTokenIdentities"></param>
 257        /// <param name="baseAuthorizationPolicies">Collection of IAuthorizationPolicies that were created by WCF.</para
 258        private static void EliminateTransportTokenPolicy(
 259            SecurityToken transportToken,
 260            IEnumerable<ClaimsIdentity> tranportTokenIdentities,
 261            List<IAuthorizationPolicy> baseAuthorizationPolicies)
 262        {
 0263            if (transportToken == null)
 264            {
 0265                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(transportToken));
 266            }
 267
 0268            if (tranportTokenIdentities == null)
 269            {
 0270                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(tranportTokenIdentities));
 271            }
 272
 0273            if (baseAuthorizationPolicies == null)
 274            {
 0275                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(baseAuthorizationPolicies));
 276            }
 277
 0278            if (baseAuthorizationPolicies.Count == 0)
 279            {
 280                // This should never happen in our current configuration. IDFx token handlers do not validate
 281                // client tokens present at the transport level. So we should atleast have one IAuthorizationPolicy
 282                // that WCF generated for the transport token.
 0283                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(nameof(baseAuthorizationPolicies), SR.Forma
 284            }
 285
 286            //
 287            // We will process one IAuthorizationPolicy at a time. Transport token will have been authenticated
 288            // by WCF and would have created a IAuthorizationPolicy for the same. If the transport token is a X.509
 289            // SecurityToken and 'mapToWindows' was set to true then the IAuthorizationPolicy that was created
 290            // by WCF will have two Claimsets, a X509ClaimSet and a WindowsClaimSet. We need to prune out this case
 291            // and ignore both these Claimsets as we have made a call to the token handler to authenticate this
 292            // token above. If we create a AuthorizationContext using all the IAuthorizationPolicies then all
 293            // the claimsets are merged and it becomes hard to identify this case.
 294            //
 0295            IAuthorizationPolicy policyToEliminate = null;
 0296            foreach (IAuthorizationPolicy authPolicy in baseAuthorizationPolicies)
 297            {
 0298                if (DoesPolicyMatchTransportToken(transportToken, tranportTokenIdentities, authPolicy))
 299                {
 0300                    policyToEliminate = authPolicy;
 0301                    break;
 302                }
 303            }
 304
 0305            if (policyToEliminate == null)
 306            {
 0307                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInvalidOperation(SR.Format(SR.ID4271, transportToken
 308            }
 309
 0310            baseAuthorizationPolicies.Remove(policyToEliminate);
 0311        }
 312
 313        /// <summary>
 314        /// Returns true if the IAuthorizationPolicy could have been created from the given Transport token.
 315        /// The method can handle only X509SecurityToken and WindowsSecurityToken.
 316        /// </summary>
 317        /// <param name="transportToken">Client's Security Token provided at the transport layer.</param>
 318        /// <param name="tranportTokenIdentities">A collection of <see cref="ClaimsIdentity"/> to match.</param>
 319        /// <param name="authPolicy">IAuthorizationPolicy to check.</param>
 320        /// <returns>True if the IAuthorizationPolicy could have been created from the given Transpor token.</returns>
 321        private static bool DoesPolicyMatchTransportToken(
 322            SecurityToken transportToken,
 323            IEnumerable<ClaimsIdentity> tranportTokenIdentities,
 324            IAuthorizationPolicy authPolicy
 325            )
 326        {
 0327            if (transportToken == null)
 328            {
 0329                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(transportToken));
 330            }
 331
 0332            if (tranportTokenIdentities == null)
 333            {
 0334                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(tranportTokenIdentities));
 335            }
 336
 0337            if (authPolicy == null)
 338            {
 0339                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(authPolicy));
 340            }
 341
 342            //////////////////////////////////////////////////////////////////////////////////////////
 343            //
 344            // There are 5 Client Authentication types at the transport layer. Each of these will
 345            // result either in a WindowsSecurityToken, X509SecurityToken or UserNameSecurityToken.
 346            //
 347            //      ClientCredential Type     ||        Transport Token Type
 348            // -------------------------------------------------------------------
 349            //          Basic                 ->        UserNameSecurityToken (In Self-hosted case)
 350            //          Basic                 ->        WindowsSecurityToken (In Web-Hosted case)
 351            //          NTLM                  ->        WindowsSecurityToken
 352            //          Negotiate             ->        WindowsSecurityToken
 353            //          Windows               ->        WindowsSecurityToken
 354            //          Certificate           ->        X509SecurityToken
 355            //
 356            //////////////////////////////////////////////////////////////////////////////////////////
 357
 0358            SysAuthorizationContext defaultAuthContext = SysAuthorizationContext.CreateDefaultAuthorizationContext(new L
 359
 0360            foreach (CoreWCF.IdentityModel.Claims.ClaimSet claimset in defaultAuthContext.ClaimSets)
 361            {
 0362                if (transportToken is X509SecurityToken x509SecurityToken)
 363                {
 364                    // Check if the claimset contains a claim that matches the X.509 certificate thumbprint.
 0365                    if (claimset.ContainsClaim(new CoreWCF.IdentityModel.Claims.Claim(
 0366                            CoreWCF.IdentityModel.Claims.ClaimTypes.Thumbprint,
 0367                            x509SecurityToken.Certificate.GetCertHash(),
 0368                            CoreWCF.IdentityModel.Claims.Rights.PossessProperty)))
 369                    {
 0370                        return true;
 371                    }
 372                }
 373                else
 374                {
 375                    // For WindowsSecurityToken and UserNameSecurityToken check that IClaimsdentity.Name
 376                    // matches the Name Claim in the ClaimSet.
 377                    // In most cases, we will have only one Identity in the ClaimsIdentityCollection
 378                    // generated from transport token.
 0379                    foreach (ClaimsIdentity transportTokenIdentity in tranportTokenIdentities)
 380                    {
 0381                        if (claimset.ContainsClaim(new CoreWCF.IdentityModel.Claims.Claim(
 0382                                CoreWCF.IdentityModel.Claims.ClaimTypes.Name,
 0383                                transportTokenIdentity.Name,
 0384                                CoreWCF.IdentityModel.Claims.Rights.PossessProperty), new ClaimStringValueComparer()))
 385                        {
 0386                            return true;
 387                        }
 388                    }
 389                }
 390            }
 391
 0392            return false;
 0393        }
 394
 395        /// <summary>
 396        /// Converts a given set of WCF IAuthorizationPolicy to WIF ClaimIdentities.
 397        /// </summary>
 398        /// <param name="authorizationPolicies">Set of AuthorizationPolicies to convert to IDFx.</param>
 399        /// <param name="securityTokenHandlerCollection">The SecurityTokenHandlerCollection to use.</param>
 400        /// <returns>ClaimsIdentityCollection</returns>
 401        private static ReadOnlyCollection<ClaimsIdentity> ConvertToIDFxIdentities(IList<IAuthorizationPolicy> authorizat
 402                                                                 SecurityTokenHandlerCollection securityTokenHandlerColl
 403        {
 0404            throw new NotImplementedException();
 405        }
 406
 407        /// <summary>
 408        /// Gets the ServiceCredentials from the OperationContext.
 409        /// </summary>
 410        /// <returns>ServiceCredentials</returns>
 411        private static ServiceCredentials GetServiceCredentials()
 412        {
 0413            ServiceCredentials serviceCredentials = null;
 414
 0415            if (OperationContext.Current != null &&
 0416                OperationContext.Current.Host != null &&
 0417                OperationContext.Current.Host.Description != null &&
 0418                OperationContext.Current.Host.Description.Behaviors != null)
 419            {
 0420                serviceCredentials = OperationContext.Current.Host.Description.Behaviors.Find<ServiceCredentials>();
 421            }
 422
 0423            return serviceCredentials;
 424        }
 425
 426        // Adds an Authentication Method claims to the given ClaimsIdentity if one is not already present.
 427        private static void AddAuthenticationMethod(ClaimsIdentity claimsIdentity, string authenticationMethod)
 428        {
 0429            System.Security.Claims.Claim authenticationMethodClaim =
 0430                        claimsIdentity.Claims.FirstOrDefault(claim => claim.Type == System.Security.Claims.ClaimTypes.Au
 431
 0432            if (authenticationMethodClaim == null)
 433            {
 434                // AuthenticationMethod claims does not exist. Add one.
 0435                claimsIdentity.AddClaim(
 0436                    new System.Security.Claims.Claim(
 0437                        System.Security.Claims.ClaimTypes.AuthenticationMethod, authenticationMethod));
 438            }
 0439        }
 440
 441        // Adds an Authentication Method claims to the given ClaimsIdentity if one is not already present.
 442        private static void AddAuthenticationInstantClaim(ClaimsIdentity claimsIdentity, string authenticationInstant)
 443        {
 444            // the issuer for this claim should always be the default issuer.
 0445            string issuerName = ClaimsIdentity.DefaultIssuer;
 0446            System.Security.Claims.Claim authenticationInstantClaim =
 0447                    claimsIdentity.Claims.FirstOrDefault(claim => claim.Type == System.Security.Claims.ClaimTypes.Authen
 448
 0449            if (authenticationInstantClaim == null)
 450            {
 451                // AuthenticationInstance claims does not exist. Add one.
 0452                claimsIdentity.AddClaim(
 0453                    new System.Security.Claims.Claim(
 0454                        System.Security.Claims.ClaimTypes.AuthenticationInstant, authenticationInstant, ClaimValueTypes.
 0455                        issuerName));
 456            }
 0457        }
 458
 459        // When a token creates more than one Identity we have to merge these identities.
 460        // The below method takes two Identities and will return a single identity. If one of the
 461        // Identities is a WindowsIdentity then all claims from the other identity are
 462        // merged into the WindowsIdentity. If neither are WindowsIdentity then it
 463        // selects 'identity1' and merges all the claims from 'identity2' into 'identity1'.
 464        //
 465        // It is not clear how we can handler duplicate name claim types and delegates.
 466        // So, we are just cloning the claims from one identity and adding it to another.
 467        internal static ClaimsIdentity MergeClaims(ClaimsIdentity identity1, ClaimsIdentity identity2)
 468        {
 0469            if ((identity1 == null) && (identity2 == null))
 470            {
 0471                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInvalidOperation(SR.Format(SR.ID4268));
 472            }
 473
 0474            if (identity1 == null)
 475            {
 0476                return identity2;
 477            }
 478
 0479            if (identity2 == null)
 480            {
 0481                return identity1;
 482            }
 483
 0484            if (identity1 is WindowsIdentity windowsIdentity)
 485            {
 0486                windowsIdentity.AddClaims(identity2.Claims);
 0487                return windowsIdentity;
 488            }
 489
 0490            windowsIdentity = identity2 as WindowsIdentity;
 0491            if (windowsIdentity != null)
 492            {
 0493                windowsIdentity.AddClaims(identity1.Claims);
 0494                return windowsIdentity;
 495            }
 496
 0497            identity1.AddClaims(identity2.Claims);
 498
 0499            return identity1;
 500        }
 501
 502        /// <summary>
 503        /// Checks authorization for the given operation context based on policy evaluation.
 504        /// </summary>
 505        /// <param name="operationContext">The OperationContext for the current authorization request.</param>
 506        /// <returns>true if authorized, false otherwise</returns>
 507        protected override ValueTask<bool> CheckAccessCoreAsync(OperationContext operationContext)
 508        {
 0509            throw new NotImplementedException();
 510        }
 511    }
 512
 513    internal class ClaimStringValueComparer : IEqualityComparer<CoreWCF.IdentityModel.Claims.Claim>
 514    {
 515        #region IEqualityComparer<CoreWCF.IdentityModel.Claims.Claim> Members
 516
 517        public bool Equals(CoreWCF.IdentityModel.Claims.Claim claim1, CoreWCF.IdentityModel.Claims.Claim claim2)
 518        {
 519            if (ReferenceEquals(claim1, claim2))
 520            {
 521                return true;
 522            }
 523
 524            if (claim1 == null || claim2 == null)
 525            {
 526                return false;
 527            }
 528
 529            if (claim1.ClaimType != claim2.ClaimType || claim1.Right != claim2.Right)
 530            {
 531                return false;
 532            }
 533
 534            return StringComparer.OrdinalIgnoreCase.Equals(claim1.Resource, claim2.Resource);
 535        }
 536
 537        public int GetHashCode(CoreWCF.IdentityModel.Claims.Claim claim)
 538        {
 539            if (claim == null)
 540            {
 541                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(claim));
 542            }
 543
 544            return claim.ClaimType.GetHashCode() ^ claim.Right.GetHashCode()
 545                ^ ((claim.Resource == null) ? 0 : claim.Resource.GetHashCode());
 546        }
 547
 548        #endregion
 549    }
 550
 551    internal class SecurityTokenSpecificationEnumerable : IEnumerable<SecurityTokenSpecification>
 552    {
 553        private readonly SecurityMessageProperty _securityMessageProperty;
 554
 555        public SecurityTokenSpecificationEnumerable(SecurityMessageProperty securityMessageProperty)
 556        {
 557            _securityMessageProperty = securityMessageProperty ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperAr
 558        }
 559
 560        public IEnumerator<SecurityTokenSpecification> GetEnumerator()
 561        {
 562            if (_securityMessageProperty.InitiatorToken != null)
 563            {
 564                yield return _securityMessageProperty.InitiatorToken;
 565            }
 566
 567            if (_securityMessageProperty.ProtectionToken != null)
 568            {
 569                yield return _securityMessageProperty.ProtectionToken;
 570            }
 571
 572            if (_securityMessageProperty.HasIncomingSupportingTokens)
 573            {
 574                foreach (SecurityTokenSpecification tokenSpecification in _securityMessageProperty.IncomingSupportingTok
 575                {
 576                    if (tokenSpecification != null)
 577                    {
 578                        yield return tokenSpecification;
 579                    }
 580                }
 581            }
 582        }
 583
 584        IEnumerator IEnumerable.GetEnumerator()
 585        {
 586            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
 587        }
 588
 589    }
 590
 591}