< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Security.SspiNegotiationTokenAuthenticator
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/SspiNegotiationTokenAuthenticator.cs
Line coverage
4%
Covered lines: 8
Uncovered lines: 187
Coverable lines: 195
Total lines: 406
Line coverage: 4.1%
Branch coverage
0%
Covered branches: 0
Total branches: 64
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/SspiNegotiationTokenAuthenticator.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 CoreWCF.Channels;
 5using CoreWCF.Diagnostics;
 6using CoreWCF.Dispatcher;
 7using CoreWCF.IdentityModel;
 8using CoreWCF.IdentityModel.Policy;
 9using CoreWCF.Runtime;
 10using CoreWCF.Security.Tokens;
 11using System;
 12using System.Collections.Generic;
 13using System.Collections.ObjectModel;
 14using System.IO;
 15using System.Runtime.Serialization;
 16using System.Security.Authentication.ExtendedProtection;
 17using System.Security.Cryptography;
 18using System.Threading.Tasks;
 19using System.Xml;
 20using CanonicalizationDriver = CoreWCF.IdentityModel.CanonicalizationDriver;
 21using Psha1DerivedKeyGenerator = CoreWCF.IdentityModel.Psha1DerivedKeyGenerator;
 22
 23namespace CoreWCF.Security
 24{
 25    internal abstract class SspiNegotiationTokenAuthenticator : NegotiationTokenAuthenticator<SspiNegotiationTokenAuthen
 26    {
 27        private string _defaultServiceBinding;
 28
 29        protected SspiNegotiationTokenAuthenticator()
 130            : base()
 31        {
 132        }
 33
 134        public ExtendedProtectionPolicy ExtendedProtectionPolicy { get; set; }
 35
 136        protected object ThisLock { get; } = new object();
 37
 38        public string DefaultServiceBinding
 39        {
 40            get
 41            {
 042                if (_defaultServiceBinding == null)
 43                {
 044                    lock (ThisLock)
 45                    {
 046                        if (_defaultServiceBinding == null)
 47                        {
 048                            _defaultServiceBinding = SecurityUtils.GetSpnFromIdentity(
 049                                                            SecurityUtils.CreateWindowsIdentity(),
 050                                                            new EndpointAddress(ListenUri));
 51                        }
 052                    }
 53                }
 54
 055                return _defaultServiceBinding;
 56            }
 057            set { _defaultServiceBinding = value; }
 58        }
 59
 60        // abstract methods
 61        public abstract XmlDictionaryString NegotiationValueType { get; }
 62        protected abstract ValueTask<ReadOnlyCollection<IAuthorizationPolicy>> ValidateSspiNegotiationAsync(ISspiNegotia
 63        protected abstract SspiNegotiationTokenAuthenticatorState CreateSspiState(byte[] incomingBlob, string incomingVa
 64
 65        // helpers
 66        protected virtual void IssueServiceToken(SspiNegotiationTokenAuthenticatorState sspiState, ReadOnlyCollection<IA
 67            out int issuedKeySize)
 68        {
 069            UniqueId contextId = SecurityUtils.GenerateUniqueId();
 070            string id = SecurityUtils.GenerateId();
 071            if (sspiState.RequestedKeySize == 0)
 72            {
 073                issuedKeySize = SecurityAlgorithmSuite.DefaultSymmetricKeyLength;
 74            }
 75            else
 76            {
 077                issuedKeySize = sspiState.RequestedKeySize;
 78            }
 079            byte[] key = new byte[issuedKeySize / 8];
 080            CryptoHelper.FillRandomBytes(key);
 081            DateTime effectiveTime = DateTime.UtcNow;
 082            DateTime expirationTime = TimeoutHelper.Add(effectiveTime, ServiceTokenLifetime);
 083            serviceToken = IssueSecurityContextToken(contextId, id, key, effectiveTime, expirationTime, authorizationPol
 084            proofToken = new WrappedKeySecurityToken(string.Empty, key, sspiState.SspiNegotiation);
 085        }
 86
 87        protected virtual void ValidateIncomingBinaryNegotiation(BinaryNegotiation incomingNego)
 88        {
 089            if (incomingNego == null)
 90            {
 091                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(SR.Format(SR.
 92            }
 093            incomingNego.Validate(NegotiationValueType);
 094        }
 95
 96        protected virtual BinaryNegotiation GetOutgoingBinaryNegotiation(ISspiNegotiation sspiNegotiation, byte[] outgoi
 97        {
 098            return new BinaryNegotiation(NegotiationValueType, outgoingBlob);
 99        }
 100
 101        private static void AddToDigest(IncrementalHash negotiationDigest, Stream stream)
 102        {
 0103            stream.Flush();
 0104            stream.Seek(0, SeekOrigin.Begin);
 0105            CanonicalizationDriver canonicalizer = new CanonicalizationDriver();
 0106            canonicalizer.SetInput(stream);
 0107            byte[] canonicalizedData = canonicalizer.GetBytes();
 0108            lock (negotiationDigest)
 109            {
 0110                negotiationDigest.AppendData(canonicalizedData);
 0111            }
 0112        }
 113
 114        private static void AddToDigest(SspiNegotiationTokenAuthenticatorState sspiState, RequestSecurityToken rst)
 115        {
 0116            MemoryStream stream = new MemoryStream();
 0117            XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream);
 0118            rst.RequestSecurityTokenXml.WriteTo(writer);
 0119            writer.Flush();
 0120            AddToDigest(sspiState.NegotiationDigest, stream);
 0121        }
 122
 123        private static void AddToDigest(SspiNegotiationTokenAuthenticatorState sspiState, RequestSecurityTokenResponse r
 124        {
 0125            MemoryStream stream = new MemoryStream();
 0126            XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream);
 0127            if (wasReceived)
 128            {
 0129                rstr.RequestSecurityTokenResponseXml.WriteTo(writer);
 130            }
 131            else
 132            {
 0133                rstr.WriteTo(writer);
 134            }
 0135            writer.Flush();
 0136            AddToDigest(sspiState.NegotiationDigest, stream);
 0137        }
 138
 139        private static byte[] ComputeAuthenticator(SspiNegotiationTokenAuthenticatorState sspiState, byte[] key)
 140        {
 141            byte[] negotiationHash;
 0142            lock (sspiState.NegotiationDigest)
 143            {
 0144                negotiationHash = sspiState.NegotiationDigest.GetHashAndReset();
 0145            }
 0146            Psha1DerivedKeyGenerator generator = new Psha1DerivedKeyGenerator(key);
 0147            return generator.GenerateDerivedKey(SecurityUtils.CombinedHashLabel, negotiationHash, 256, 0);
 148        }
 149
 150        // overrides
 151        protected override bool IsMultiLegNegotiation
 152        {
 153            get
 154            {
 0155                return true;
 156            }
 157        }
 158
 159        protected override Binding GetNegotiationBinding(Binding binding)
 160        {
 0161            return binding;
 162        }
 163
 164        protected override MessageFilter GetListenerFilter()
 165        {
 1166            return new SspiNegotiationFilter(this);
 167        }
 168
 169        protected override async ValueTask<(BodyWriter, SspiNegotiationTokenAuthenticatorState)> ProcessRequestSecurityT
 170        {
 0171            if (request == null)
 172            {
 0173                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(request));
 174            }
 0175            if (requestSecurityToken == null)
 176            {
 0177                throw TraceUtility.ThrowHelperArgumentNull(nameof(requestSecurityToken), request);
 178            }
 0179            if (requestSecurityToken.RequestType != null && requestSecurityToken.RequestType != StandardsManager.TrustDr
 180            {
 0181                throw TraceUtility.ThrowHelperWarning(new SecurityNegotiationException(SR.Format(SR.InvalidRstRequestTyp
 182            }
 0183            BinaryNegotiation incomingNego = requestSecurityToken.GetBinaryNegotiation();
 0184            ValidateIncomingBinaryNegotiation(incomingNego);
 0185            SspiNegotiationTokenAuthenticatorState negotiationState = CreateSspiState(incomingNego.GetNegotiationData(),
 0186            AddToDigest(negotiationState, requestSecurityToken);
 0187            negotiationState.Context = requestSecurityToken.Context;
 0188            if (requestSecurityToken.KeySize != 0)
 189            {
 0190                WSTrust.Driver.ValidateRequestedKeySize(requestSecurityToken.KeySize, SecurityAlgorithmSuite);
 191            }
 0192            negotiationState.RequestedKeySize = requestSecurityToken.KeySize;
 193            string appliesToNamespace;
 194            string appliesToName;
 0195            requestSecurityToken.GetAppliesToQName(out appliesToName, out appliesToNamespace);
 0196            if (appliesToName == AddressingStrings.EndpointReference && appliesToNamespace == request.Version.Addressing
 197            {
 198                DataContractSerializer serializer;
 0199                if (request.Version.Addressing == AddressingVersion.WSAddressing10)
 200                {
 0201                    serializer = DataContractSerializerDefaults.CreateSerializer(typeof(EndpointAddress10), DataContract
 0202                    negotiationState.AppliesTo = requestSecurityToken.GetAppliesTo<EndpointAddress10>(serializer).ToEndp
 203                }
 0204                else if (request.Version.Addressing == AddressingVersion.WSAddressingAugust2004)
 205                {
 0206                    serializer = DataContractSerializerDefaults.CreateSerializer(typeof(EndpointAddressAugust2004), Data
 0207                    negotiationState.AppliesTo = requestSecurityToken.GetAppliesTo<EndpointAddressAugust2004>(serializer
 208                }
 209                else
 210                {
 0211                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 0212                        new ProtocolException(SR.Format(SR.AddressingVersionNotSupported, request.Version.Addressing)));
 213                }
 214
 0215                negotiationState.AppliesToSerializer = serializer;
 216            }
 0217            var bodyWriter = await ProcessNegotiationAsync(negotiationState, request, incomingNego);
 0218            return (bodyWriter, negotiationState);
 0219        }
 220
 221        protected override ValueTask<BodyWriter> ProcessRequestSecurityTokenResponseAsync(SspiNegotiationTokenAuthentica
 222        {
 0223            if (request == null)
 224            {
 0225                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(request));
 226            }
 0227            if (requestSecurityTokenResponse == null)
 228            {
 0229                throw TraceUtility.ThrowHelperArgumentNull(nameof(requestSecurityTokenResponse), request);
 230            }
 0231            if (requestSecurityTokenResponse.Context != negotiationState.Context)
 232            {
 0233                throw TraceUtility.ThrowHelperError(new SecurityNegotiationException(SR.Format(SR.BadSecurityNegotiation
 234            }
 0235            AddToDigest(negotiationState, requestSecurityTokenResponse, true);
 0236            BinaryNegotiation incomingNego = requestSecurityTokenResponse.GetBinaryNegotiation();
 0237            ValidateIncomingBinaryNegotiation(incomingNego);
 0238            return ProcessNegotiationAsync(negotiationState, request, incomingNego);
 239        }
 240
 241        private async ValueTask<BodyWriter> ProcessNegotiationAsync(SspiNegotiationTokenAuthenticatorState negotiationSt
 242        {
 0243            ISspiNegotiation sspiNegotiation = negotiationState.SspiNegotiation;
 244
 0245            byte[] outgoingBlob = sspiNegotiation.GetOutgoingBlob(incomingNego.GetNegotiationData(),
 0246                                                            SecurityUtils.GetChannelBindingFromMessage(incomingMessage),
 0247                                                            ExtendedProtectionPolicy);
 248
 0249            if (sspiNegotiation.IsValidContext == false)
 250            {
 0251                throw TraceUtility.ThrowHelperError(new SecurityNegotiationException(SR.Format(SR.InvalidSspiNegotiation
 252            }
 253            // if there is no blob to send back the nego must be complete from the server side
 0254            if (outgoingBlob == null && sspiNegotiation.IsCompleted == false)
 255            {
 0256                throw TraceUtility.ThrowHelperError(new SecurityNegotiationException(SR.Format(SR.NoBinaryNegoToSend)), 
 257            }
 258            BinaryNegotiation outgoingBinaryNegotiation;
 0259            if (outgoingBlob != null)
 260            {
 0261                outgoingBinaryNegotiation = GetOutgoingBinaryNegotiation(sspiNegotiation, outgoingBlob);
 262            }
 263            else
 264            {
 0265                outgoingBinaryNegotiation = null;
 266            }
 267            BodyWriter replyBody;
 0268            if (sspiNegotiation.IsCompleted)
 269            {
 0270                ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies = await ValidateSspiNegotiationAsync(sspi
 271                SecurityContextSecurityToken serviceToken;
 272                WrappedKeySecurityToken proofToken;
 273                int issuedKeySize;
 0274                IssueServiceToken(negotiationState, authorizationPolicies, out serviceToken, out proofToken, out issuedK
 0275                negotiationState.SetServiceToken(serviceToken);
 276
 0277                SecurityKeyIdentifierClause externalTokenReference = IssuedSecurityTokenParameters.CreateKeyIdentifierCl
 0278                SecurityKeyIdentifierClause internalTokenReference = IssuedSecurityTokenParameters.CreateKeyIdentifierCl
 279
 0280                RequestSecurityTokenResponse dummyRstr = new RequestSecurityTokenResponse(StandardsManager)
 0281                {
 0282                    Context = negotiationState.Context,
 0283                    KeySize = issuedKeySize,
 0284                    TokenType = SecurityContextTokenUri
 0285                };
 0286                if (outgoingBinaryNegotiation != null)
 287                {
 0288                    dummyRstr.SetBinaryNegotiation(outgoingBinaryNegotiation);
 289                }
 0290                dummyRstr.RequestedUnattachedReference = externalTokenReference;
 0291                dummyRstr.RequestedAttachedReference = internalTokenReference;
 0292                dummyRstr.SetLifetime(serviceToken.ValidFrom, serviceToken.ValidTo);
 0293                if (negotiationState.AppliesTo != null)
 294                {
 0295                    if (incomingMessage.Version.Addressing == AddressingVersion.WSAddressing10)
 296                    {
 0297                        dummyRstr.SetAppliesTo<EndpointAddress10>(EndpointAddress10.FromEndpointAddress(
 0298                            negotiationState.AppliesTo),
 0299                            negotiationState.AppliesToSerializer);
 300                    }
 0301                    else if (incomingMessage.Version.Addressing == AddressingVersion.WSAddressingAugust2004)
 302                    {
 0303                        dummyRstr.SetAppliesTo<EndpointAddressAugust2004>(EndpointAddressAugust2004.FromEndpointAddress(
 0304                            negotiationState.AppliesTo),
 0305                            negotiationState.AppliesToSerializer);
 306                    }
 307                    else
 308                    {
 0309                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 0310                            new ProtocolException(SR.Format(SR.AddressingVersionNotSupported, incomingMessage.Version.Ad
 311                    }
 312                }
 0313                dummyRstr.MakeReadOnly();
 0314                AddToDigest(negotiationState, dummyRstr, false);
 0315                RequestSecurityTokenResponse negotiationRstr = new RequestSecurityTokenResponse(StandardsManager)
 0316                {
 0317                    RequestedSecurityToken = serviceToken,
 0318
 0319                    RequestedProofToken = proofToken,
 0320                    Context = negotiationState.Context,
 0321                    KeySize = issuedKeySize,
 0322                    TokenType = SecurityContextTokenUri
 0323                };
 0324                if (outgoingBinaryNegotiation != null)
 325                {
 0326                    negotiationRstr.SetBinaryNegotiation(outgoingBinaryNegotiation);
 327                }
 0328                negotiationRstr.RequestedAttachedReference = internalTokenReference;
 0329                negotiationRstr.RequestedUnattachedReference = externalTokenReference;
 0330                if (negotiationState.AppliesTo != null)
 331                {
 0332                    if (incomingMessage.Version.Addressing == AddressingVersion.WSAddressing10)
 333                    {
 0334                        negotiationRstr.SetAppliesTo<EndpointAddress10>(
 0335                            EndpointAddress10.FromEndpointAddress(negotiationState.AppliesTo),
 0336                            negotiationState.AppliesToSerializer);
 337                    }
 0338                    else if (incomingMessage.Version.Addressing == AddressingVersion.WSAddressingAugust2004)
 339                    {
 0340                        negotiationRstr.SetAppliesTo<EndpointAddressAugust2004>(
 0341                            EndpointAddressAugust2004.FromEndpointAddress(negotiationState.AppliesTo),
 0342                            negotiationState.AppliesToSerializer);
 343                    }
 344                    else
 345                    {
 0346                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 0347                            new ProtocolException(SR.Format(SR.AddressingVersionNotSupported, incomingMessage.Version.Ad
 348                    }
 349                }
 0350                negotiationRstr.MakeReadOnly();
 351
 0352                byte[] authenticator = ComputeAuthenticator(negotiationState, serviceToken.GetKeyBytes());
 0353                RequestSecurityTokenResponse authenticatorRstr = new RequestSecurityTokenResponse(StandardsManager)
 0354                {
 0355                    Context = negotiationState.Context
 0356                };
 0357                authenticatorRstr.SetAuthenticator(authenticator);
 0358                authenticatorRstr.MakeReadOnly();
 359
 0360                List<RequestSecurityTokenResponse> rstrList = new List<RequestSecurityTokenResponse>(2)
 0361                {
 0362                    negotiationRstr,
 0363                    authenticatorRstr
 0364                };
 0365                replyBody = new RequestSecurityTokenResponseCollection(rstrList, StandardsManager);
 366
 367            }
 368            else
 369            {
 0370                RequestSecurityTokenResponse rstr = new RequestSecurityTokenResponse(StandardsManager)
 0371                {
 0372                    Context = negotiationState.Context
 0373                };
 0374                rstr.SetBinaryNegotiation(outgoingBinaryNegotiation);
 0375                rstr.MakeReadOnly();
 0376                AddToDigest(negotiationState, rstr, false);
 0377                replyBody = rstr;
 378            }
 379
 0380            return replyBody;
 0381        }
 382
 383        private class SspiNegotiationFilter : HeaderFilter
 384        {
 385            private readonly SspiNegotiationTokenAuthenticator _authenticator;
 386
 1387            public SspiNegotiationFilter(SspiNegotiationTokenAuthenticator authenticator)
 388            {
 1389                _authenticator = authenticator;
 1390            }
 391
 392            public override bool Match(Message message)
 393            {
 0394                if (message.Headers.Action == _authenticator.RequestSecurityTokenAction.Value
 0395                    || message.Headers.Action == _authenticator.RequestSecurityTokenResponseAction.Value)
 396                {
 0397                    return !SecurityVersion.Default.DoesMessageContainSecurityHeader(message);
 398                }
 399                else
 400                {
 0401                    return false;
 402                }
 403            }
 404        }
 405    }
 406}