< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Security.SecurityAppliedMessage
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/SecurityAppliedMessage.cs
Line coverage
21%
Covered lines: 56
Uncovered lines: 200
Coverable lines: 256
Total lines: 547
Line coverage: 21.8%
Branch coverage
23%
Covered branches: 13
Total branches: 56
Branch coverage: 23.2%
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/SecurityAppliedMessage.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.IO;
 6using System.Security.Cryptography;
 7using System.Threading.Tasks;
 8using System.Xml;
 9using CoreWCF.Channels;
 10using CoreWCF.IdentityModel.Tokens;
 11using CoreWCF.Runtime;
 12using CoreWCF.Security.Tokens;
 13using IPrefixGenerator = CoreWCF.IdentityModel.IPrefixGenerator;
 14using ISecurityElement = CoreWCF.IdentityModel.ISecurityElement;
 15using XmlAttributeHolder = CoreWCF.IdentityModel.XmlAttributeHolder;
 16
 17namespace CoreWCF.Security
 18{
 19    internal sealed class SecurityAppliedMessage : DelegatingMessage
 20    {
 21        private bool _bodyIdInserted;
 6322        private string _bodyPrefix = MessageStrings.Prefix;
 23        private XmlBuffer _fullBodyBuffer;
 24        private ISecurityElement _encryptedBodyContent;
 25        private XmlAttributeHolder[] _bodyAttributes;
 26        private bool _delayedApplicationHandled;
 27        private BodyState _state = BodyState.Created;
 28        private readonly SendSecurityHeader _securityHeader;
 29        private MemoryStream _startBodyFragment;
 30        private MemoryStream _endBodyFragment;
 31        private byte[] _fullBodyFragment;
 32        private int _fullBodyFragmentLength;
 33
 34        public SecurityAppliedMessage(Message messageToProcess, SendSecurityHeader securityHeader, bool signBody, bool e
 6335            : base(messageToProcess)
 36        {
 37            Fx.Assert(!(messageToProcess is SecurityAppliedMessage), "SecurityAppliedMessage should not be wrapped");
 6338            _securityHeader = securityHeader;
 6339            BodyProtectionMode = MessagePartProtectionModeHelper.GetProtectionMode(signBody, encryptBody, securityHeader
 6340        }
 41
 042        public string BodyId { get; private set; }
 43
 6344        public MessagePartProtectionMode BodyProtectionMode { get; }
 45
 046        internal byte[] PrimarySignatureValue => _securityHeader.PrimarySignatureValue;
 47
 48        private Exception CreateBadStateException(string operation)
 49        {
 050            return new InvalidOperationException(SR.Format(SR.MessageBodyOperationNotValidInBodyState,
 051                operation, _state));
 52        }
 53
 54        private void EnsureUniqueSecurityApplication()
 55        {
 6356            if (_delayedApplicationHandled)
 57            {
 058                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.Del
 59            }
 6360            _delayedApplicationHandled = true;
 6361        }
 62
 63        protected override void OnBodyToString(XmlDictionaryWriter writer)
 64        {
 065            if (_state == BodyState.Created || _fullBodyFragment != null)
 66            {
 067                base.OnBodyToString(writer);
 68            }
 69            else
 70            {
 071                OnWriteBodyContents(writer);
 72            }
 073        }
 74
 75        protected override void OnClose()
 76        {
 77            try
 78            {
 1079                InnerMessage.Close();
 1080            }
 81            finally
 82            {
 1083                _fullBodyBuffer = null;
 1084                _bodyAttributes = null;
 1085                _encryptedBodyContent = null;
 1086                _state = BodyState.Disposed;
 1087            }
 1088        }
 89
 90        protected override void OnWriteStartBody(XmlDictionaryWriter writer)
 91        {
 6392            if (_startBodyFragment != null || _fullBodyFragment != null)
 93            {
 094                WriteStartInnerMessageWithId(writer);
 095                return;
 96            }
 97
 6398            switch (_state)
 99            {
 100                case BodyState.Created:
 101                case BodyState.Encrypted:
 63102                    InnerMessage.WriteStartBody(writer);
 63103                    return;
 104                case BodyState.Signed:
 105                case BodyState.EncryptedThenSigned:
 0106                    XmlDictionaryReader reader = _fullBodyBuffer.GetReader(0);
 0107                    writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
 0108                    writer.WriteAttributes(reader, false);
 0109                    reader.Close();
 0110                    return;
 111                case BodyState.SignedThenEncrypted:
 0112                    writer.WriteStartElement(_bodyPrefix, XD.MessageDictionary.Body, Version.Envelope.DictionaryNamespac
 0113                    if (_bodyAttributes != null)
 114                    {
 0115                        XmlAttributeHolder.WriteAttributes(_bodyAttributes, writer);
 116                    }
 0117                    return;
 118                default:
 0119                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBadStateException(nameof(OnWriteStar
 120            }
 121        }
 122
 123        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
 124        {
 63125            switch (_state)
 126            {
 127                case BodyState.Created:
 63128                    InnerMessage.WriteBodyContents(writer);
 63129                    return;
 130                case BodyState.Signed:
 131                case BodyState.EncryptedThenSigned:
 0132                    XmlDictionaryReader reader = _fullBodyBuffer.GetReader(0);
 0133                    reader.ReadStartElement();
 0134                    while (reader.NodeType != XmlNodeType.EndElement)
 135                    {
 0136                        writer.WriteNode(reader, false);
 137                    }
 138
 0139                    reader.ReadEndElement();
 0140                    reader.Close();
 0141                    return;
 142                case BodyState.Encrypted:
 143                case BodyState.SignedThenEncrypted:
 0144                    _encryptedBodyContent.WriteTo(writer, ServiceModelDictionaryManager.Instance);
 0145                    break;
 146                default:
 0147                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBadStateException(nameof(OnWriteBody
 148            }
 149        }
 150
 151        public override async Task OnWriteMessageAsync(XmlDictionaryWriter writer)
 152        {
 153            // With NetFx the writer passed to SecurityAppliedMessage.OnWriteMessageAsync is of type XmlUtf8TextWriter w
 154            // On .NET, the type is XmlDictionaryAsyncCheckWriter which wraps XmlUtf8TextWriter, both of which do implem
 2155            if (Environment.Version.MajorRevision < 8)
 156            {
 2157                OnWriteMessage(writer);
 2158                return;
 159            }
 160
 161            // For Kerb one shot, the channel binding will be need to be fished out of the message, cached and added to 
 162            // token before calling ISC.
 163
 0164            AttachChannelBindingTokenIfFound();
 165
 0166            EnsureUniqueSecurityApplication();
 167
 0168            MessagePrefixGenerator prefixGenerator = new MessagePrefixGenerator(writer);
 0169            _securityHeader.StartSecurityApplication();
 170
 0171            Headers.Add(_securityHeader);
 172
 0173            InnerMessage.WriteStartEnvelope(writer);
 174
 0175            Headers.RemoveAt(Headers.Count - 1);
 176
 0177            await _securityHeader.ApplyBodySecurityAsync(writer, prefixGenerator);
 178
 0179            InnerMessage.WriteStartHeaders(writer);
 0180            await _securityHeader.ApplySecurityAndWriteHeadersAsync(Headers, writer, prefixGenerator);
 181
 0182            _securityHeader.RemoveSignatureEncryptionIfAppropriate();
 183
 0184            _securityHeader.CompleteSecurityApplication();
 0185            _securityHeader.WriteHeader(writer, Version);
 0186            await writer.WriteEndElementAsync();
 187
 0188            if (_fullBodyFragment != null)
 189            {
 0190                ((IFragmentCapableXmlDictionaryWriter)writer).WriteFragment(_fullBodyFragment, 0, _fullBodyFragmentLengt
 191            }
 192            else
 193            {
 0194                if (_startBodyFragment != null)
 195                {
 0196                    ((IFragmentCapableXmlDictionaryWriter)writer).WriteFragment(_startBodyFragment.GetBuffer(), 0, (int)
 197                }
 198                else
 199                {
 0200                    OnWriteStartBody(writer);
 201                }
 202
 0203                OnWriteBodyContents(writer);
 204
 0205                if (_endBodyFragment != null)
 206                {
 0207                    ((IFragmentCapableXmlDictionaryWriter)writer).WriteFragment(_endBodyFragment.GetBuffer(), 0, (int)_e
 208                }
 209                else
 210                {
 0211                    await writer.WriteEndElementAsync();
 212                }
 213            }
 214
 0215            await writer.WriteEndElementAsync();
 2216        }
 217
 218        protected override void OnWriteMessage(XmlDictionaryWriter writer)
 219        {
 220            // For Kerb one shot, the channel binding will be need to be fished out of the message, cached and added to 
 221            // token before calling ISC.
 222
 63223            AttachChannelBindingTokenIfFound();
 224
 63225            EnsureUniqueSecurityApplication();
 226
 63227            MessagePrefixGenerator prefixGenerator = new MessagePrefixGenerator(writer);
 63228            _securityHeader.StartSecurityApplication();
 229
 63230            Headers.Add(_securityHeader);
 231
 63232            InnerMessage.WriteStartEnvelope(writer);
 233
 63234            Headers.RemoveAt(Headers.Count - 1);
 235
 63236            _securityHeader.ApplyBodySecurity(writer, prefixGenerator);
 237
 63238            InnerMessage.WriteStartHeaders(writer);
 63239            _securityHeader.ApplySecurityAndWriteHeaders(Headers, writer, prefixGenerator);
 240
 63241            _securityHeader.RemoveSignatureEncryptionIfAppropriate();
 242
 63243            _securityHeader.CompleteSecurityApplication();
 63244            _securityHeader.WriteHeader(writer, Version);
 63245            writer.WriteEndElement();
 246
 63247            if (_fullBodyFragment != null)
 248            {
 0249                ((IFragmentCapableXmlDictionaryWriter)writer).WriteFragment(_fullBodyFragment, 0, _fullBodyFragmentLengt
 250            }
 251            else
 252            {
 63253                if (_startBodyFragment != null)
 254                {
 0255                    ((IFragmentCapableXmlDictionaryWriter)writer).WriteFragment(_startBodyFragment.GetBuffer(), 0, (int)
 256                }
 257                else
 258                {
 63259                    OnWriteStartBody(writer);
 260                }
 261
 63262                OnWriteBodyContents(writer);
 263
 63264                if (_endBodyFragment != null)
 265                {
 0266                    ((IFragmentCapableXmlDictionaryWriter)writer).WriteFragment(_endBodyFragment.GetBuffer(), 0, (int)_e
 267                }
 268                else
 269                {
 63270                    writer.WriteEndElement();
 271                }
 272            }
 273
 63274            writer.WriteEndElement();
 63275        }
 276
 277        private void AttachChannelBindingTokenIfFound()
 278        {
 63279            ChannelBindingMessageProperty.TryGet(InnerMessage, out ChannelBindingMessageProperty cbmp);
 280
 63281            if (cbmp != null)
 282            {
 0283                if (_securityHeader.ElementContainer != null && _securityHeader.ElementContainer.EndorsingSupportingToke
 284                {
 0285                    foreach (SecurityToken token in _securityHeader.ElementContainer.EndorsingSupportingTokens)
 286                    {
 0287                        if (token is ProviderBackedSecurityToken pbst)
 288                        {
 0289                            pbst.ChannelBinding = cbmp.ChannelBinding;
 290                        }
 291                    }
 292                }
 293            }
 63294        }
 295
 296        private void SetBodyId()
 297        {
 0298            BodyId = InnerMessage.GetBodyAttribute(
 0299                UtilityStrings.IdAttribute,
 0300                _securityHeader.StandardsManager.IdManager.DefaultIdNamespaceUri);
 0301            if (BodyId == null)
 302            {
 0303                BodyId = _securityHeader.GenerateId();
 0304                _bodyIdInserted = true;
 305            }
 0306        }
 307
 308        public void WriteBodyToEncrypt(EncryptedData encryptedData, SymmetricAlgorithm algorithm)
 309        {
 0310            encryptedData.Id = _securityHeader.GenerateId();
 311
 0312            BodyContentHelper helper = new BodyContentHelper();
 0313            XmlDictionaryWriter encryptingWriter = helper.CreateWriter();
 0314            InnerMessage.WriteBodyContents(encryptingWriter);
 0315            encryptedData.SetUpEncryption(algorithm, helper.ExtractResult());
 0316            _encryptedBodyContent = encryptedData;
 317
 0318            _state = BodyState.Encrypted;
 0319        }
 320
 321        public void WriteBodyToEncryptThenSign(Stream canonicalStream, EncryptedData encryptedData, SymmetricAlgorithm a
 322        {
 0323            encryptedData.Id = _securityHeader.GenerateId();
 0324            SetBodyId();
 325
 0326            XmlDictionaryWriter encryptingWriter = XmlDictionaryWriter.CreateTextWriter(Stream.Null);
 327            // The XmlSerializer body formatter would add a
 328            // document declaration to the body fragment when a fresh writer
 329            // is provided. Hence, insert a dummy element here and capture
 330            // the body contents as a fragment.
 0331            encryptingWriter.WriteStartElement("a");
 0332            MemoryStream ms = new MemoryStream();
 0333            ((IFragmentCapableXmlDictionaryWriter)encryptingWriter).StartFragment(ms, true);
 334
 0335            InnerMessage.WriteBodyContents(encryptingWriter);
 0336            ((IFragmentCapableXmlDictionaryWriter)encryptingWriter).EndFragment();
 0337            encryptingWriter.WriteEndElement();
 0338            ms.Flush();
 0339            encryptedData.SetUpEncryption(algorithm, new ArraySegment<byte>(ms.GetBuffer(), 0, (int)ms.Length));
 340
 0341            _fullBodyBuffer = new XmlBuffer(int.MaxValue);
 0342            XmlDictionaryWriter canonicalWriter = _fullBodyBuffer.OpenSection(XmlDictionaryReaderQuotas.Max);
 343
 0344            canonicalWriter.StartCanonicalization(canonicalStream, false, null);
 0345            WriteStartInnerMessageWithId(canonicalWriter);
 0346            encryptedData.WriteTo(canonicalWriter, ServiceModelDictionaryManager.Instance);
 0347            canonicalWriter.WriteEndElement();
 0348            canonicalWriter.EndCanonicalization();
 0349            canonicalWriter.Flush();
 350
 0351            _fullBodyBuffer.CloseSection();
 0352            _fullBodyBuffer.Close();
 353
 0354            _state = BodyState.EncryptedThenSigned;
 0355        }
 356
 357        public void WriteBodyToSign(Stream canonicalStream)
 358        {
 0359            SetBodyId();
 360
 0361            _fullBodyBuffer = new XmlBuffer(int.MaxValue);
 0362            XmlDictionaryWriter canonicalWriter = _fullBodyBuffer.OpenSection(XmlDictionaryReaderQuotas.Max);
 0363            canonicalWriter.StartCanonicalization(canonicalStream, false, null);
 0364            WriteInnerMessageWithId(canonicalWriter);
 0365            canonicalWriter.EndCanonicalization();
 0366            canonicalWriter.Flush();
 0367            _fullBodyBuffer.CloseSection();
 0368            _fullBodyBuffer.Close();
 369
 0370            _state = BodyState.Signed;
 0371        }
 372
 373        public async ValueTask WriteBodyToSignAsync(Stream canonicalStream)
 374        {
 0375            SetBodyId();
 376
 0377            _fullBodyBuffer = new XmlBuffer(int.MaxValue);
 0378            XmlDictionaryWriter canonicalWriter = _fullBodyBuffer.OpenSection(XmlDictionaryReaderQuotas.Max);
 0379            canonicalWriter.StartCanonicalization(canonicalStream, false, null);
 0380            WriteInnerMessageWithId(canonicalWriter);
 0381            canonicalWriter.EndCanonicalization();
 0382            await canonicalWriter.FlushAsync();
 0383            _fullBodyBuffer.CloseSection();
 0384            _fullBodyBuffer.Close();
 385
 0386            _state = BodyState.Signed;
 0387        }
 388
 389        public void WriteBodyToSignThenEncrypt(Stream canonicalStream, EncryptedData encryptedData, SymmetricAlgorithm a
 390        {
 0391            XmlBuffer buffer = new XmlBuffer(int.MaxValue);
 0392            XmlDictionaryWriter fragmentingWriter = buffer.OpenSection(XmlDictionaryReaderQuotas.Max);
 0393            WriteBodyToSignThenEncryptWithFragments(canonicalStream, false, null, encryptedData, algorithm, fragmentingW
 0394            ((IFragmentCapableXmlDictionaryWriter)fragmentingWriter).WriteFragment(_startBodyFragment.GetBuffer(), 0, (i
 0395            ((IFragmentCapableXmlDictionaryWriter)fragmentingWriter).WriteFragment(_endBodyFragment.GetBuffer(), 0, (int
 0396            buffer.CloseSection();
 0397            buffer.Close();
 398
 0399            _startBodyFragment = null;
 0400            _endBodyFragment = null;
 401
 0402            XmlDictionaryReader reader = buffer.GetReader(0);
 0403            reader.MoveToContent();
 0404            _bodyPrefix = reader.Prefix;
 0405            if (reader.HasAttributes)
 406            {
 0407                _bodyAttributes = XmlAttributeHolder.ReadAttributes(reader);
 408            }
 0409            reader.Close();
 0410        }
 411
 412        public void WriteBodyToSignThenEncryptWithFragments(
 413            Stream stream, bool includeComments, string[] inclusivePrefixes,
 414            EncryptedData encryptedData, SymmetricAlgorithm algorithm, XmlDictionaryWriter writer)
 415        {
 0416            IFragmentCapableXmlDictionaryWriter fragmentingWriter = (IFragmentCapableXmlDictionaryWriter)writer;
 417
 0418            SetBodyId();
 0419            encryptedData.Id = _securityHeader.GenerateId();
 420
 0421            _startBodyFragment = new MemoryStream();
 0422            BufferedOutputStream bodyContentFragment = new BufferManagerOutputStream(SRCommon.XmlBufferQuotaExceeded, 10
 0423            _endBodyFragment = new MemoryStream();
 424
 0425            writer.StartCanonicalization(stream, includeComments, inclusivePrefixes);
 426
 0427            fragmentingWriter.StartFragment(_startBodyFragment, false);
 0428            WriteStartInnerMessageWithId(writer);
 0429            fragmentingWriter.EndFragment();
 430
 0431            fragmentingWriter.StartFragment(bodyContentFragment, true);
 0432            InnerMessage.WriteBodyContents(writer);
 0433            fragmentingWriter.EndFragment();
 434
 0435            fragmentingWriter.StartFragment(_endBodyFragment, false);
 0436            writer.WriteEndElement();
 0437            fragmentingWriter.EndFragment();
 438
 0439            writer.EndCanonicalization();
 440
 0441            byte[] bodyBuffer = bodyContentFragment.ToArray(out int bodyLength);
 442
 0443            encryptedData.SetUpEncryption(algorithm, new ArraySegment<byte>(bodyBuffer, 0, bodyLength));
 0444            _encryptedBodyContent = encryptedData;
 445
 0446            _state = BodyState.SignedThenEncrypted;
 0447        }
 448
 449        public void WriteBodyToSignWithFragments(Stream stream, bool includeComments, string[] inclusivePrefixes, XmlDic
 450        {
 0451            IFragmentCapableXmlDictionaryWriter fragmentingWriter = (IFragmentCapableXmlDictionaryWriter)writer;
 452
 0453            SetBodyId();
 0454            BufferedOutputStream fullBodyFragment = new BufferManagerOutputStream(SRCommon.XmlBufferQuotaExceeded, 1024,
 0455            writer.StartCanonicalization(stream, includeComments, inclusivePrefixes);
 0456            fragmentingWriter.StartFragment(fullBodyFragment, false);
 0457            WriteStartInnerMessageWithId(writer);
 0458            InnerMessage.WriteBodyContents(writer);
 0459            writer.WriteEndElement();
 0460            fragmentingWriter.EndFragment();
 0461            writer.EndCanonicalization();
 462
 0463            _fullBodyFragment = fullBodyFragment.ToArray(out _fullBodyFragmentLength);
 464
 0465            _state = BodyState.Signed;
 0466        }
 467
 468        public async ValueTask WriteBodyToSignWithFragmentsAsync(Stream stream, bool includeComments, string[] inclusive
 469        {
 0470            IFragmentCapableXmlDictionaryWriter fragmentingWriter = (IFragmentCapableXmlDictionaryWriter)writer;
 471
 0472            SetBodyId();
 0473            BufferedOutputStream fullBodyFragment = new BufferManagerOutputStream(SRCommon.XmlBufferQuotaExceeded, 1024,
 0474            writer.StartCanonicalization(stream, includeComments, inclusivePrefixes);
 0475            fragmentingWriter.StartFragment(fullBodyFragment, false);
 0476            WriteStartInnerMessageWithId(writer);
 0477            await InnerMessage.WriteBodyContentsAsync(writer);
 0478            await writer.WriteEndElementAsync();
 0479            fragmentingWriter.EndFragment();
 0480            writer.EndCanonicalization();
 481
 0482            _fullBodyFragment = fullBodyFragment.ToArray(out _fullBodyFragmentLength);
 483
 0484            _state = BodyState.Signed;
 0485        }
 486
 487        private void WriteInnerMessageWithId(XmlDictionaryWriter writer)
 488        {
 0489            WriteStartInnerMessageWithId(writer);
 0490            InnerMessage.WriteBodyContents(writer);
 0491            writer.WriteEndElement();
 0492        }
 493
 494        private void WriteStartInnerMessageWithId(XmlDictionaryWriter writer)
 495        {
 0496            InnerMessage.WriteStartBody(writer);
 0497            if (_bodyIdInserted)
 498            {
 0499                _securityHeader.StandardsManager.IdManager.WriteIdAttribute(writer, BodyId);
 500            }
 0501        }
 502
 503        private enum BodyState
 504        {
 505            Created,
 506            Signed,
 507            SignedThenEncrypted,
 508            EncryptedThenSigned,
 509            Encrypted,
 510            Disposed,
 511        }
 512
 513        private struct BodyContentHelper
 514        {
 515            private MemoryStream _stream;
 516            private XmlDictionaryWriter _writer;
 517
 518            public XmlDictionaryWriter CreateWriter()
 519            {
 0520                _stream = new MemoryStream();
 0521                _writer = XmlDictionaryWriter.CreateTextWriter(_stream);
 0522                return _writer;
 523            }
 524
 525            public ArraySegment<byte> ExtractResult()
 526            {
 0527                _writer.Flush();
 0528                return new ArraySegment<byte>(_stream.GetBuffer(), 0, (int)_stream.Length);
 529            }
 530        }
 531
 532        private sealed class MessagePrefixGenerator : IPrefixGenerator
 533        {
 534            private readonly XmlWriter _writer;
 535
 63536            public MessagePrefixGenerator(XmlWriter writer)
 537            {
 63538                _writer = writer;
 63539            }
 540
 541            public string GetPrefix(string namespaceUri, int depth, bool isForAttribute)
 542            {
 0543                return _writer.LookupPrefix(namespaceUri);
 544            }
 545        }
 546    }
 547}