< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Security.SecurityVerifiedMessage
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/SecurityVerifiedMessage.cs
Line coverage
12%
Covered lines: 23
Uncovered lines: 156
Coverable lines: 179
Total lines: 570
Line coverage: 12.8%
Branch coverage
9%
Covered branches: 7
Total branches: 72
Branch coverage: 9.7%
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/SecurityVerifiedMessage.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.Diagnostics;
 6using System.IO;
 7using System.Xml;
 8using CoreWCF.Channels;
 9using CoreWCF.Diagnostics;
 10using CoreWCF.Runtime;
 11
 12namespace CoreWCF.Security
 13{
 14    internal sealed class SecurityVerifiedMessage : DelegatingMessage
 15    {
 16        private byte[] _decryptedBuffer;
 17        private XmlDictionaryReader _cachedDecryptedBodyContentReader;
 18        private XmlAttributeHolder[] _envelopeAttributes;
 19        private XmlAttributeHolder[] _headerAttributes;
 20        private XmlAttributeHolder[] _bodyAttributes;
 21        private string _envelopePrefix;
 22        private bool _bodyDecrypted;
 23        private BodyState _state = BodyState.Created;
 24        private string _bodyPrefix;
 25        private bool _isDecryptedBodyStatusDetermined;
 26        private bool _isDecryptedBodyFault;
 27        private bool _isDecryptedBodyEmpty;
 28        private XmlDictionaryReader _cachedReaderAtSecurityHeader;
 29        private XmlBuffer _messageBuffer;
 30        private bool _canDelegateCreateBufferedCopyToInnerMessage;
 31
 32        public SecurityVerifiedMessage(Message messageToProcess, ReceiveSecurityHeader securityHeader)
 9433            : base(messageToProcess)
 34        {
 9435            ReceivedSecurityHeader = securityHeader;
 9436            if (securityHeader.RequireMessageProtection)
 37            {
 38                XmlDictionaryReader messageReader;
 039                if (InnerMessage is BufferedMessage bufferedMessage && Headers.ContainsOnlyBufferedMessageHeaders)
 40                {
 041                    messageReader = bufferedMessage.GetMessageReader();
 42                }
 43                else
 44                {
 045                    _messageBuffer = new XmlBuffer(int.MaxValue);
 046                    XmlDictionaryWriter writer = _messageBuffer.OpenSection(ReceivedSecurityHeader.ReaderQuotas);
 047                    InnerMessage.WriteMessage(writer);
 048                    _messageBuffer.CloseSection();
 049                    _messageBuffer.Close();
 050                    messageReader = _messageBuffer.GetReader(0);
 51                }
 052                MoveToSecurityHeader(messageReader, securityHeader.HeaderIndex, true);
 053                _cachedReaderAtSecurityHeader = messageReader;
 054                _state = BodyState.Buffered;
 55            }
 56            else
 57            {
 9458                _envelopeAttributes = XmlAttributeHolder.emptyArray;
 9459                _headerAttributes = XmlAttributeHolder.emptyArray;
 9460                _bodyAttributes = XmlAttributeHolder.emptyArray;
 9461                _canDelegateCreateBufferedCopyToInnerMessage = true;
 62            }
 9463        }
 64
 65        public override bool IsEmpty
 66        {
 67            get
 68            {
 10669                if (IsDisposed)
 70                {
 071                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
 72                }
 10673                if (!_bodyDecrypted)
 74                {
 10675                    return InnerMessage.IsEmpty;
 76                }
 77
 078                EnsureDecryptedBodyStatusDetermined();
 79
 080                return _isDecryptedBodyEmpty;
 81            }
 82        }
 83
 84        public override bool IsFault
 85        {
 86            get
 87            {
 088                if (IsDisposed)
 89                {
 090                    throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
 91                }
 092                if (!_bodyDecrypted)
 93                {
 094                    return InnerMessage.IsFault;
 95                }
 96
 097                EnsureDecryptedBodyStatusDetermined();
 98
 099                return _isDecryptedBodyFault;
 100            }
 101        }
 102
 0103        internal byte[] PrimarySignatureValue => ReceivedSecurityHeader.PrimarySignatureValue;
 104
 94105        internal ReceiveSecurityHeader ReceivedSecurityHeader { get; }
 106
 107        private Exception CreateBadStateException(string operation)
 108        {
 0109            return new InvalidOperationException(SR.Format(SR.MessageBodyOperationNotValidInBodyState,
 0110                operation, _state));
 111        }
 112
 113        public XmlDictionaryReader CreateFullBodyReader()
 114        {
 0115            switch (_state)
 116            {
 117                case BodyState.Buffered:
 0118                    return CreateFullBodyReaderFromBufferedState();
 119                case BodyState.Decrypted:
 0120                    return CreateFullBodyReaderFromDecryptedState();
 121                default:
 0122                    throw TraceUtility.ThrowHelperError(CreateBadStateException("CreateFullBodyReader"), this);
 123            }
 124        }
 125
 126        private XmlDictionaryReader CreateFullBodyReaderFromBufferedState()
 127        {
 0128            if (_messageBuffer != null)
 129            {
 0130                XmlDictionaryReader reader = _messageBuffer.GetReader(0);
 0131                MoveToBody(reader);
 0132                return reader;
 133            }
 134            else
 135            {
 0136                return ((BufferedMessage)InnerMessage).GetBufferedReaderAtBody();
 137            }
 138        }
 139
 140        private XmlDictionaryReader CreateFullBodyReaderFromDecryptedState()
 141        {
 0142            XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(_decryptedBuffer, 0, _decryptedBuffer.Leng
 0143            MoveToBody(reader);
 0144            return reader;
 145        }
 146
 147        private void EnsureDecryptedBodyStatusDetermined()
 148        {
 0149            if (!_isDecryptedBodyStatusDetermined)
 150            {
 0151                XmlDictionaryReader reader = CreateFullBodyReader();
 0152                if (ReadStartBody(reader, InnerMessage.Version.Envelope, out _isDecryptedBodyFault, out _isDecryptedBody
 153                {
 0154                    _cachedDecryptedBodyContentReader = reader;
 155                }
 156                else
 157                {
 0158                    reader.Close();
 159                }
 0160                _isDecryptedBodyStatusDetermined = true;
 161            }
 0162        }
 163
 164        public XmlAttributeHolder[] GetEnvelopeAttributes()
 165        {
 0166            return _envelopeAttributes;
 167        }
 168
 169        public XmlAttributeHolder[] GetHeaderAttributes()
 170        {
 0171            return _headerAttributes;
 172        }
 173
 174        private XmlDictionaryReader GetReaderAtEnvelope()
 175        {
 0176            if (_messageBuffer != null)
 177            {
 0178                return _messageBuffer.GetReader(0);
 179            }
 180            else
 181            {
 0182                return ((BufferedMessage)InnerMessage).GetMessageReader();
 183            }
 184        }
 185
 186        public XmlDictionaryReader GetReaderAtFirstHeader()
 187        {
 0188            XmlDictionaryReader reader = GetReaderAtEnvelope();
 0189            MoveToHeaderBlock(reader, false);
 0190            reader.ReadStartElement();
 0191            return reader;
 192        }
 193
 194        public XmlDictionaryReader GetReaderAtSecurityHeader()
 195        {
 94196            if (_cachedReaderAtSecurityHeader != null)
 197            {
 0198                XmlDictionaryReader result = _cachedReaderAtSecurityHeader;
 0199                _cachedReaderAtSecurityHeader = null;
 0200                return result;
 201            }
 94202            return Headers.GetReaderAtHeader(ReceivedSecurityHeader.HeaderIndex);
 203        }
 204
 205        private void MoveToBody(XmlDictionaryReader reader)
 206        {
 0207            if (reader.NodeType != XmlNodeType.Element)
 208            {
 0209                reader.MoveToContent();
 210            }
 0211            reader.ReadStartElement();
 0212            if (reader.IsStartElement(XD.MessageDictionary.Header, Version.Envelope.DictionaryNamespace))
 213            {
 0214                reader.Skip();
 215            }
 0216            if (reader.NodeType != XmlNodeType.Element)
 217            {
 0218                reader.MoveToContent();
 219            }
 0220        }
 221
 222        private void MoveToHeaderBlock(XmlDictionaryReader reader, bool captureAttributes)
 223        {
 0224            if (reader.NodeType != XmlNodeType.Element)
 225            {
 0226                reader.MoveToContent();
 227            }
 0228            if (captureAttributes)
 229            {
 0230                _envelopePrefix = reader.Prefix;
 0231                _envelopeAttributes = XmlAttributeHolder.ReadAttributes(reader);
 232            }
 0233            reader.ReadStartElement();
 0234            reader.MoveToStartElement(XD.MessageDictionary.Header, Version.Envelope.DictionaryNamespace);
 0235            if (captureAttributes)
 236            {
 0237                _headerAttributes = XmlAttributeHolder.ReadAttributes(reader);
 238            }
 0239        }
 240
 241        private void MoveToSecurityHeader(XmlDictionaryReader reader, int headerIndex, bool captureAttributes)
 242        {
 0243            MoveToHeaderBlock(reader, captureAttributes);
 0244            reader.ReadStartElement();
 0245            while (true)
 246            {
 0247                if (reader.NodeType != XmlNodeType.Element)
 248                {
 0249                    reader.MoveToContent();
 250                }
 0251                if (headerIndex == 0)
 252                {
 253                    break;
 254                }
 0255                reader.Skip();
 0256                headerIndex--;
 257            }
 0258        }
 259
 260        protected override void OnBodyToString(XmlDictionaryWriter writer)
 261        {
 0262            if (_state == BodyState.Created)
 263            {
 0264                base.OnBodyToString(writer);
 265            }
 266            else
 267            {
 0268                OnWriteBodyContents(writer);
 269            }
 0270        }
 271
 272        protected override void OnClose()
 273        {
 63274            if (_cachedDecryptedBodyContentReader != null)
 275            {
 276                try
 277                {
 0278                    _cachedDecryptedBodyContentReader.Close();
 0279                }
 280                catch (System.IO.IOException exception)
 281                {
 282                    //
 283                    // We only want to catch and log the I/O exception here
 284                    // assuming reader only throw those exceptions
 285                    //
 0286                    DiagnosticUtility.TraceHandledException(exception, TraceEventType.Warning);
 0287                }
 288                finally
 289                {
 0290                    _cachedDecryptedBodyContentReader = null;
 0291                }
 292            }
 293
 63294            if (_cachedReaderAtSecurityHeader != null)
 295            {
 296                try
 297                {
 0298                    _cachedReaderAtSecurityHeader.Close();
 0299                }
 300                catch (System.IO.IOException exception)
 301                {
 302                    //
 303                    // We only want to catch and log the I/O exception here
 304                    // assuming reader only throw those exceptions
 305                    //
 0306                    DiagnosticUtility.TraceHandledException(exception, TraceEventType.Warning);
 0307                }
 308                finally
 309                {
 0310                    _cachedReaderAtSecurityHeader = null;
 0311                }
 312            }
 313
 63314            _messageBuffer = null;
 63315            _decryptedBuffer = null;
 63316            _state = BodyState.Disposed;
 63317            InnerMessage.Close();
 63318        }
 319
 320        protected override XmlDictionaryReader OnGetReaderAtBodyContents()
 321        {
 63322            if (_state == BodyState.Created)
 323            {
 63324                return InnerMessage.GetReaderAtBodyContents();
 325            }
 0326            if (_bodyDecrypted)
 327            {
 0328                EnsureDecryptedBodyStatusDetermined();
 329            }
 0330            if (_cachedDecryptedBodyContentReader != null)
 331            {
 0332                XmlDictionaryReader result = _cachedDecryptedBodyContentReader;
 0333                _cachedDecryptedBodyContentReader = null;
 0334                return result;
 335            }
 336            else
 337            {
 0338                XmlDictionaryReader reader = CreateFullBodyReader();
 0339                reader.ReadStartElement();
 0340                reader.MoveToContent();
 0341                return reader;
 342            }
 343        }
 344
 345        protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
 346        {
 0347            if (_canDelegateCreateBufferedCopyToInnerMessage && InnerMessage is BufferedMessage)
 348            {
 0349                return InnerMessage.CreateBufferedCopy(maxBufferSize);
 350            }
 351            else
 352            {
 0353                return base.OnCreateBufferedCopy(maxBufferSize);
 354            }
 355        }
 356
 357        internal void OnMessageProtectionPassComplete(bool atLeastOneHeaderOrBodyEncrypted)
 358        {
 0359            _canDelegateCreateBufferedCopyToInnerMessage = !atLeastOneHeaderOrBodyEncrypted;
 0360        }
 361
 362        internal void OnUnencryptedPart(string name, string ns)
 363        {
 0364            if (ns == null)
 365            {
 0366                throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.Format(SR.RequiredMessagePartNotEncr
 367            }
 368            else
 369            {
 0370                throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.Format(SR.RequiredMessagePartNotEncr
 371            }
 372        }
 373
 374        internal void OnUnsignedPart(string name, string ns)
 375        {
 0376            if (ns == null)
 377            {
 0378                throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.Format(SR.RequiredMessagePartNotSign
 379            }
 380            else
 381            {
 0382                throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.Format(SR.RequiredMessagePartNotSign
 383            }
 384        }
 385
 386        protected override void OnWriteStartBody(XmlDictionaryWriter writer)
 387        {
 0388            if (_state == BodyState.Created)
 389            {
 0390                InnerMessage.WriteStartBody(writer);
 0391                return;
 392            }
 393
 0394            XmlDictionaryReader reader = CreateFullBodyReader();
 0395            reader.MoveToContent();
 0396            writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
 0397            writer.WriteAttributes(reader, false);
 0398            reader.Close();
 0399        }
 400
 401        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
 402        {
 0403            if (_state == BodyState.Created)
 404            {
 0405                InnerMessage.WriteBodyContents(writer);
 0406                return;
 407            }
 408
 0409            XmlDictionaryReader reader = CreateFullBodyReader();
 0410            reader.ReadStartElement();
 0411            while (reader.NodeType != XmlNodeType.EndElement)
 412            {
 0413                writer.WriteNode(reader, false);
 414            }
 415
 0416            reader.ReadEndElement();
 0417            reader.Close();
 0418        }
 419
 420        public void SetBodyPrefixAndAttributes(XmlDictionaryReader bodyReader)
 421        {
 0422            _bodyPrefix = bodyReader.Prefix;
 0423            _bodyAttributes = XmlAttributeHolder.ReadAttributes(bodyReader);
 0424        }
 425
 426        public void SetDecryptedBody(byte[] decryptedBodyContent)
 427        {
 0428            if (_state != BodyState.Buffered)
 429            {
 0430                throw TraceUtility.ThrowHelperError(CreateBadStateException("SetDecryptedBody"), this);
 431            }
 432
 0433            MemoryStream stream = new MemoryStream();
 0434            XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream);
 435
 0436            writer.WriteStartElement(_envelopePrefix, XD.MessageDictionary.Envelope, Version.Envelope.DictionaryNamespac
 0437            XmlAttributeHolder.WriteAttributes(_envelopeAttributes, writer);
 438
 0439            writer.WriteStartElement(_bodyPrefix, XD.MessageDictionary.Body, Version.Envelope.DictionaryNamespace);
 0440            XmlAttributeHolder.WriteAttributes(_bodyAttributes, writer);
 0441            writer.WriteString(" "); // ensure non-empty element
 0442            writer.WriteEndElement();
 0443            writer.WriteEndElement();
 0444            writer.Flush();
 445
 0446            _decryptedBuffer = ContextImportHelper.SpliceBuffers(decryptedBodyContent, stream.GetBuffer(), (int)stream.L
 447
 0448            _bodyDecrypted = true;
 0449            _state = BodyState.Decrypted;
 0450        }
 451
 452        private enum BodyState
 453        {
 454            Created,
 455            Buffered,
 456            Decrypted,
 457            Disposed,
 458        }
 459    }
 460
 461    //TODO investigate
 462    // Adding wrapping tags using a writer is a temporary feature to
 463    // support interop with a partner.  Eventually, the serialization
 464    // team will add a feature to XmlUTF8TextReader to directly
 465    // support the addition of outer namespaces before creating a
 466    // Reader.  This roundabout way of supporting context-sensitive
 467    // decryption can then be removed.
 468    internal static class ContextImportHelper
 469    {
 470        internal static XmlDictionaryReader CreateSplicedReader(byte[] decryptedBuffer,
 471            XmlAttributeHolder[] outerContext1, XmlAttributeHolder[] outerContext2, XmlAttributeHolder[] outerContext3, 
 472        {
 473            const string wrapper1 = "x";
 474            const string wrapper2 = "y";
 475            const string wrapper3 = "z";
 476            const int wrappingDepth = 3;
 477
 478            MemoryStream stream = new MemoryStream();
 479            XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream);
 480            writer.WriteStartElement(wrapper1);
 481            WriteNamespaceDeclarations(outerContext1, writer);
 482            writer.WriteStartElement(wrapper2);
 483            WriteNamespaceDeclarations(outerContext2, writer);
 484            writer.WriteStartElement(wrapper3);
 485            WriteNamespaceDeclarations(outerContext3, writer);
 486            writer.WriteString(" "); // ensure non-empty element
 487            writer.WriteEndElement();
 488            writer.WriteEndElement();
 489            writer.WriteEndElement();
 490            writer.Flush();
 491
 492            byte[] splicedBuffer = SpliceBuffers(decryptedBuffer, stream.GetBuffer(), (int)stream.Length, wrappingDepth)
 493            XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(splicedBuffer, quotas);
 494            reader.ReadStartElement(wrapper1);
 495            reader.ReadStartElement(wrapper2);
 496            reader.ReadStartElement(wrapper3);
 497            if (reader.NodeType != XmlNodeType.Element)
 498            {
 499                reader.MoveToContent();
 500            }
 501            return reader;
 502        }
 503
 504        internal static string GetPrefixIfNamespaceDeclaration(string prefix, string localName)
 505        {
 506            if (prefix == "xmlns")
 507            {
 508                return localName;
 509            }
 510            if (prefix.Length == 0 && localName == "xmlns")
 511            {
 512                return string.Empty;
 513            }
 514            return null;
 515        }
 516
 517        private static bool IsNamespaceDeclaration(string prefix, string localName)
 518        {
 519            return GetPrefixIfNamespaceDeclaration(prefix, localName) != null;
 520        }
 521
 522        internal static byte[] SpliceBuffers(byte[] middle, byte[] wrapper, int wrapperLength, int wrappingDepth)
 523        {
 524            const byte openChar = (byte)'<';
 525            int openCharsFound = 0;
 526            int openCharIndex;
 527            for (openCharIndex = wrapperLength - 1; openCharIndex >= 0; openCharIndex--)
 528            {
 529                if (wrapper[openCharIndex] == openChar)
 530                {
 531                    openCharsFound++;
 532                    if (openCharsFound == wrappingDepth)
 533                    {
 534                        break;
 535                    }
 536                }
 537            }
 538
 539            Fx.Assert(openCharIndex > 0, "");
 540
 541            byte[] splicedBuffer = Fx.AllocateByteArray(checked(middle.Length + wrapperLength - 1));
 542            int offset = 0;
 543            int count = openCharIndex - 1;
 544            Buffer.BlockCopy(wrapper, 0, splicedBuffer, offset, count);
 545            offset += count;
 546            count = middle.Length;
 547            Buffer.BlockCopy(middle, 0, splicedBuffer, offset, count);
 548            offset += count;
 549            count = wrapperLength - openCharIndex;
 550            Buffer.BlockCopy(wrapper, openCharIndex, splicedBuffer, offset, count);
 551
 552            return splicedBuffer;
 553        }
 554
 555        private static void WriteNamespaceDeclarations(XmlAttributeHolder[] attributes, XmlWriter writer)
 556        {
 557            if (attributes != null)
 558            {
 559                for (int i = 0; i < attributes.Length; i++)
 560                {
 561                    XmlAttributeHolder a = attributes[i];
 562                    if (IsNamespaceDeclaration(a.Prefix, a.LocalName))
 563                    {
 564                        a.WriteTo(writer);
 565                    }
 566                }
 567            }
 568        }
 569    }
 570}