< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Dispatcher.SecurityDuplexSessionChannelDispatcher
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Dispatcher/SecurityServiceDispatcher.cs
Line coverage
77%
Covered lines: 44
Uncovered lines: 13
Coverable lines: 57
Total lines: 719
Line coverage: 77.1%
Branch coverage
71%
Covered branches: 10
Total branches: 14
Branch coverage: 71.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%11100%
Abort()100%110%
CloseAsync()100%11100%
CloseAsync(...)100%11100%
OpenAsync()100%11100%
OpenAsync(...)100%110%
DispatchAsync(...)100%110%
DispatchAsync()100%22100%
SendAsync(...)100%11100%
SendAsync(...)100%11100%
ProcessInnerItemAsync()100%44100%
SendFaultIfRequiredAsync()50%8868.75%
TryReceiveAsync(...)100%110%
ReceiveAsync(...)100%110%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Dispatcher/SecurityServiceDispatcher.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Threading;
 7using System.Threading.Tasks;
 8using CoreWCF.Channels;
 9using CoreWCF.Configuration;
 10using CoreWCF.Runtime;
 11using CoreWCF.Security;
 12using Microsoft.Extensions.DependencyInjection;
 13
 14namespace CoreWCF.Dispatcher
 15{
 16    /// <summary>
 17    /// This is equivalent of SecurityChannelListener present in WCF codebase
 18    /// </summary>
 19    internal class SecurityServiceDispatcher : IServiceDispatcher, IDisposable
 20    {
 21        private readonly BindingContext _bindingContext;
 22        private ChannelBuilder _channelBuilder;
 23        // TODO Investigate is we need to implement ComputeEndpointIdentity, see issue #284
 24        //private readonly EndpointIdentity _identity;
 25        private SecurityProtocolFactory _securityProtocolFactory;
 26        private SecuritySessionServerSettings _sessionServerSettings;
 27        private SecurityListenerSettingsLifetimeManager _settingsLifetimeManager;
 28
 29        //ServiceChannelDispatcher to call SCT (just keep one instance)
 30        private volatile IServiceChannelDispatcher _securityAuthServiceChannelDispatcher;
 31        private Task<IServiceChannelDispatcher> _channelTask;
 32        private bool _disposed = false;
 33
 34        public SecurityServiceDispatcher(BindingContext context, IServiceDispatcher serviceDispatcher)
 35        {
 36            InnerServiceDispatcher = serviceDispatcher;
 37            _bindingContext = context;
 38            // this.securityProtocolFactory =  securityProtocolFactory; // we set it later from TransportSecurityBinding
 39            //  this.settingsLifetimeManager = new SecurityListenerSettingsLifetimeManager(this.securityProtocolFactory,
 40        }
 41
 42        internal ChannelBuilder ChannelBuilder
 43        {
 44            get
 45            {
 46                ThrowIfDisposed();
 47                return _channelBuilder;
 48            }
 49        }
 50
 51        public Uri BaseAddress => InnerServiceDispatcher.BaseAddress;
 52
 53        public Binding Binding => _bindingContext.Binding;
 54
 55        public IServiceDispatcher InnerServiceDispatcher { get; set; }
 56
 57        public IServiceDispatcher SecurityAuthServiceDispatcher { get; set; }
 58
 59        public ICollection<Type> SupportedChannelTypes => InnerServiceDispatcher.SupportedChannelTypes;
 60
 61        private AsyncLock ThisLock { get; } = new AsyncLock();
 62
 63        public SecurityProtocolFactory SecurityProtocolFactory
 64        {
 65            get
 66            {
 67                ThrowIfDisposed();
 68                return _securityProtocolFactory;
 69            }
 70            set
 71            {
 72                ThrowIfDisposed();
 73                _securityProtocolFactory = value ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nam
 74            }
 75        }
 76
 77        private void ThrowIfDisposed()
 78        {
 79            if (_disposed)
 80            {
 81                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(GetType().FullName
 82            }
 83        }
 84
 85        public bool SessionMode { get; set; }
 86
 87        internal SecuritySessionServerSettings SessionServerSettings
 88        {
 89            get
 90            {
 91                if (_sessionServerSettings == null)
 92                {
 93                    lock (ThisLock)
 94                    {
 95                        if (_sessionServerSettings == null)
 96                        {
 97                            SecuritySessionServerSettings tmp = new SecuritySessionServerSettings();
 98                            Thread.MemoryBarrier();
 99                            tmp.SecurityServiceDispatcher = this;
 100                            _sessionServerSettings = tmp;
 101                        }
 102                    }
 103                }
 104                return _sessionServerSettings;
 105            }
 106        }
 107
 108        public bool SendUnsecuredFaults { get; set; } = true;
 109
 110        public IChannel OuterChannel { get; set; }
 111
 112        public Type AcceptorChannelType { get; set; }
 113
 114        IList<Type> IServiceDispatcher.SupportedChannelTypes => throw new NotImplementedException();
 115
 116        public ServiceHostBase Host => InnerServiceDispatcher.Host;
 117
 118        internal void InitializeSecurityDispatcher(ChannelBuilder channelBuilder, Type type)
 119        {
 120            _channelBuilder = channelBuilder;
 121
 122            if (SessionMode)
 123            {
 124                _sessionServerSettings.ChannelBuilder = ChannelBuilder;
 125                //this.InnerChannelListener = this.sessionServerSettings.CreateInnerChannelListener();
 126                // this.Acceptor = this.sessionServerSettings.CreateAcceptor<TChannel>();
 127                AcceptorChannelType = type;
 128                _sessionServerSettings.AcceptorChannelType = type;
 129            }
 130            else
 131            {
 132              //  throw new PlatformNotSupportedException();
 133                //TODO later
 134                // this.InnerChannelListener = this.ChannelBuilder.BuildChannelListener<TChannel>();
 135                // this.Acceptor = (IChannelAcceptor<TChannel>)new SecurityChannelAcceptor(this,
 136                //     (IChannelListener<TChannel>)InnerChannelListener, this.securityProtocolFactory.CreateListenerSecu
 137            }
 138            //Called below method in the initialization path, in WCF it's called in Open of ServiceHost.
 139            InitializeServiceDispatcherSecurityState();
 140        }
 141
 142        private void InitializeServiceDispatcherSecurityState()
 143        {
 144            if (SessionMode)
 145            {
 146                SessionServerSettings.SessionProtocolFactory.ListenUri = InnerServiceDispatcher.BaseAddress;
 147                SessionServerSettings.SecurityServiceDispatcher = this;
 148            }
 149            else
 150            {
 151                ThrowIfProtocolFactoryNotSet();
 152                _securityProtocolFactory.ListenUri = InnerServiceDispatcher.BaseAddress;
 153            }
 154            _settingsLifetimeManager = new SecurityListenerSettingsLifetimeManager(_securityProtocolFactory, _sessionSer
 155            if (_sessionServerSettings != null)
 156            {
 157                _sessionServerSettings.SettingsLifetimeManager = _settingsLifetimeManager;
 158            }
 159            _settingsLifetimeManager.OpenAsync(ServiceDefaults.OpenTimeout).GetAwaiter().GetResult();
 160            //this.hasSecurityStateReference = true;
 161        }
 162
 163        //private
 164
 165        // This method should only be called at Open time, since it looks up the identity based on the
 166        // thread token
 167        //void ComputeEndpointIdentity()
 168        //{
 169        //    EndpointIdentity result = null;
 170        //    if (this.State == CommunicationState.Opened)
 171        //    {
 172        //        if (this.SecurityProtocolFactory != null)
 173        //        {
 174        //            result = this.SecurityProtocolFactory.GetIdentityOfSelf();
 175        //        }
 176        //        else if (this.SessionServerSettings != null && this.SessionServerSettings.SessionProtocolFactory != nu
 177        //        {
 178        //            result = this.SessionServerSettings.SessionProtocolFactory.GetIdentityOfSelf();
 179        //        }
 180        //    }
 181        //    if (result == null)
 182        //    {
 183        //        result = base.GetProperty<EndpointIdentity>();
 184        //    }
 185        //    this.identity = result;
 186        //}
 187
 188        private void ThrowIfProtocolFactoryNotSet()
 189        {
 190            if (_securityProtocolFactory == null)
 191            {
 192                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.Sec
 193            }
 194        }
 195
 196        public async Task<IServiceChannelDispatcher> CreateServiceChannelDispatcherAsync(IChannel outerChannel)
 197        {
 198            //TODO should have better logic
 199            //Initialization path start
 200            if (outerChannel.ChannelDispatcher == null && SessionMode)
 201            {
 202                TypedChannelDemuxer typedChannelDemuxer = ChannelBuilder.GetTypedChannelDemuxer(outerChannel.GetType());
 203                IServiceChannelDispatcher channelDispatcher = await typedChannelDemuxer.CreateServiceChannelDispatcherAs
 204                return channelDispatcher;
 205            }
 206            //initialization end
 207            //Below dispatches all SCT call for first time for all clients
 208            else
 209            {
 210                IServiceChannelDispatcher securityReplyChannelDispatcher = await GetInnerChannelDispatcherAsync(outerCha
 211                return securityReplyChannelDispatcher;
 212            }
 213        }
 214
 215        internal async Task<IServiceChannelDispatcher> GetAuthChannelDispatcher(IChannel outerChannel)
 216        {
 217            if (_securityAuthServiceChannelDispatcher == null)
 218            {
 219                lock (ThisLock)
 220                {
 221                    if (_channelTask == null)
 222                    {
 223                        _channelTask = SecurityAuthServiceDispatcher.CreateServiceChannelDispatcherAsync(outerChannel);
 224                    }
 225                }
 226                _securityAuthServiceChannelDispatcher = await _channelTask;
 227                Thread.MemoryBarrier();
 228            }
 229            return _securityAuthServiceChannelDispatcher;
 230        }
 231
 232
 233        /// <summary>
 234        /// Return same instance of real service channel dispatcher.
 235        /// This method is called by SecurityReplySessionServiceChannelDispatcher(SecuritySessionServerSettings) to disp
 236        /// </summary>
 237        /// <param name="outerChannel"></param>
 238        /// <returns></returns>
 239        internal Task<IServiceChannelDispatcher> GetInnerServiceChannelDispatcher(IChannel outerChannel)
 240        {
 241            lock (ThisLock)
 242            {
 243                return InnerServiceDispatcher.CreateServiceChannelDispatcherAsync(outerChannel);
 244            }
 245        }
 246
 247        //Reference OnAcceptChannel/SecurityChannelListner
 248        private async Task<IServiceChannelDispatcher> GetInnerChannelDispatcherAsync(IChannel outerChannel)
 249        {
 250            IServiceChannelDispatcher securityChannelDispatcher = null;
 251            SecurityProtocol securityProtocol = SecurityProtocolFactory.CreateSecurityProtocol(null, null,
 252            (outerChannel is IReplyChannel || outerChannel is IReplySessionChannel), TimeSpan.Zero);
 253            await securityProtocol.OpenAsync(TimeSpan.Zero);
 254            /* TODO once we add more features
 255            if (outerChannel is IInputChannel)
 256            {
 257                securityChannel = new SecurityInputChannel(listener, (IInputChannel)innerChannel, securityProtocol, list
 258            }
 259            else if (outerChannel is IInputSessionChannel))
 260            {
 261                securityChannel = new SecurityInputSessionChannel(listener, (IInputSessionChannel)innerChannel, security
 262            }
 263            else if (outerChannel is IDuplexChannel))
 264            {
 265                securityChannel = new SecurityDuplexChannel(listener, (IDuplexChannel)innerChannel, securityProtocol, li
 266            }
 267            else*/
 268            if (outerChannel is IDuplexSessionChannel duplexSessionChannel)
 269            {
 270                securityChannelDispatcher = new SecurityDuplexSessionChannelDispatcher(this, duplexSessionChannel, secur
 271            }
 272            else if (outerChannel is IReplyChannel replyChannel)
 273            {
 274                securityChannelDispatcher = new SecurityReplyChannelDispatcher(this, replyChannel, securityProtocol, _se
 275            }
 276            /* else if (listener.SupportsRequestReply && typeof(TChannel) == typeof(IReplySessionChannel))
 277             {
 278                 securityChannel = new SecurityReplySessionChannel(listener, (IReplySessionChannel)innerChannel, securit
 279             }
 280             else
 281             {
 282                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.Uns
 283             }*/
 284            return securityChannelDispatcher;
 285        }
 286
 287        public void Dispose()
 288        {
 289            if (!_disposed)
 290            {
 291                _disposed = true;
 292            }
 293        }
 294    }
 295
 296    internal abstract class ServerSecurityChannelDispatcher<UChannel> : IServiceChannelDispatcher where UChannel : class
 297    {
 298        private static MessageFault s_secureConversationCloseNotSupportedFault;
 299        private readonly IServiceProvider _serviceProvider;
 300        private readonly string _secureConversationCloseAction;
 301
 302        protected ServerSecurityChannelDispatcher(SecurityServiceDispatcher securityServiceDispatcher, UChannel innerCha
 303        {
 304            SecurityProtocol = securityProtocol;
 305            OuterChannel = (IChannel)innerChannel;
 306            _serviceProvider = OuterChannel.GetProperty<IServiceScopeFactory>().CreateScope().ServiceProvider;
 307            _secureConversationCloseAction = securityProtocol.SecurityProtocolFactory.StandardsManager.SecureConversatio
 308        }
 309
 310        internal SecurityProtocol SecurityProtocol { get; set; }
 311
 312        public IChannel OuterChannel { get; private set; }
 313
 314        public T GetProperty<T>() where T : class
 315        {
 316            T tObj = _serviceProvider.GetService<T>();
 317            if (tObj == null)
 318                return OuterChannel.GetProperty<T>();
 319            else return tObj;
 320        }
 321
 322        private static MessageFault GetSecureConversationCloseNotSupportedFault()
 323        {
 324            if (s_secureConversationCloseNotSupportedFault == null)
 325            {
 326                FaultCode faultCode = FaultCode.CreateSenderFaultCode(DotNetSecurityStrings.SecureConversationCancelNotA
 327                FaultReason faultReason = new FaultReason(SR.Format(SR.SecureConversationCancelNotAllowedFaultReason), S
 328                s_secureConversationCloseNotSupportedFault = MessageFault.CreateFault(faultCode, faultReason);
 329            }
 330            return s_secureConversationCloseNotSupportedFault;
 331        }
 332
 333        private void ThrowIfSecureConversationCloseMessage(Message message)
 334        {
 335            if (message.Headers.Action == _secureConversationCloseAction)
 336            {
 337                throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.Format(SR.Se
 338            }
 339        }
 340
 341        internal async ValueTask<(Message, SecurityProtocolCorrelationState)> VerifyIncomingMessageAsync(Message message
 342        {
 343            if (message == null)
 344            {
 345                return (null, null);
 346            }
 347            Fx.Assert(SecurityProtocol != null, "SecurityProtocol can't be null");
 348            ThrowIfSecureConversationCloseMessage(message);
 349            return await SecurityProtocol.VerifyIncomingMessageAsync(message, timeout, correlationState);
 350        }
 351
 352        internal ValueTask<Message> VerifyIncomingMessageAsync(Message message, TimeSpan timeout)
 353        {
 354            if (message == null)
 355            {
 356                return new ValueTask<Message>((Message)null);
 357            }
 358            ThrowIfSecureConversationCloseMessage(message);
 359            return SecurityProtocol.VerifyIncomingMessageAsync(message, timeout);
 360        }
 361
 362        public abstract Task DispatchAsync(RequestContext context);
 363        public abstract Task DispatchAsync(Message message);
 364    }
 365
 366    internal class SecurityReplyChannelDispatcher : ServerSecurityChannelDispatcher<IReplyChannel>, IReplyChannel
 367    {
 368        private readonly bool _sendUnsecuredFaults;
 369        internal static readonly SecurityStandardsManager s_defaultStandardsManager = SecurityStandardsManager.DefaultIn
 370
 371#pragma warning disable CS0067
 372        public event EventHandler Closed;
 373        public event EventHandler Closing;
 374        public event EventHandler Faulted;
 375        public event EventHandler Opened;
 376        public event EventHandler Opening;
 377#pragma warning restore CS0067
 378
 379        public SecurityReplyChannelDispatcher(SecurityServiceDispatcher securityServiceDispatcher, IReplyChannel innerCh
 380                : base(securityServiceDispatcher, innerChannel, securityProtocol, settingsLifetimeManager)
 381        {
 382            _sendUnsecuredFaults = securityServiceDispatcher.SendUnsecuredFaults;
 383            SecurityServiceDispatcher = securityServiceDispatcher;
 384        }
 385
 386        public EndpointAddress LocalAddress => throw new NotImplementedException();
 387
 388        public IServiceChannelDispatcher ChannelDispatcher { get; set; }
 389
 390        public SecurityServiceDispatcher SecurityServiceDispatcher { get; }
 391
 392        public CommunicationState State => OuterChannel.State;
 393
 394
 395        internal async ValueTask<RequestContext> ProcessReceivedRequestAsync(RequestContext requestContext)
 396        {
 397            if (requestContext == null)
 398            {
 399                return null;
 400            }
 401            TimeSpan timeout = ServiceDefaults.ReceiveTimeout;
 402            Message message = requestContext.RequestMessage;
 403            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 404            if (message == null)
 405            {
 406                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.Format(SR.Receiv
 407            }
 408            try
 409            {
 410                (Message message, SecurityProtocolCorrelationState correlationState) verifiedIncomingMessage = await Ver
 411                message = verifiedIncomingMessage.message;
 412                SecurityProtocolCorrelationState correlationState = verifiedIncomingMessage.correlationState;
 413
 414                if (message.Headers.RelatesTo == null && message.Headers.MessageId != null)
 415                {
 416                    message.Headers.RelatesTo = message.Headers.MessageId;
 417                }
 418                return new SecurityRequestContext(message, requestContext, SecurityProtocol, correlationState, ServiceDe
 419            }
 420            catch (Exception securityException)
 421            {
 422                await SendFaultIfRequiredAsync(securityException, requestContext, timeoutHelper.RemainingTime());
 423                throw;
 424            }
 425        }
 426
 427        private async Task SendFaultIfRequiredAsync(Exception e, RequestContext innerContext, TimeSpan timeout)
 428        {
 429            if (!_sendUnsecuredFaults)
 430            {
 431                return;
 432            }
 433            MessageFault fault = SecurityUtils.CreateSecurityMessageFault(e, SecurityProtocol.SecurityProtocolFactory.St
 434            if (fault == null)
 435            {
 436                return;
 437            }
 438            Message requestMessage = innerContext.RequestMessage;
 439            Message faultMessage = Message.CreateMessage(requestMessage.Version, fault, requestMessage.Version.Addressin
 440            try
 441            {
 442                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 443                await innerContext.ReplyAsync(faultMessage);
 444                await innerContext.CloseAsync(timeoutHelper.GetCancellationToken());
 445            }
 446            catch (Exception ex)
 447            {
 448                if (Fx.IsFatal(ex))
 449                {
 450                    throw;
 451                }
 452            }
 453            finally
 454            {
 455                faultMessage.Close();
 456                innerContext.Abort();
 457            }
 458        }
 459
 460        public override async Task DispatchAsync(RequestContext context)
 461        {
 462            SecurityRequestContext securedMessage = (SecurityRequestContext)(await ProcessReceivedRequestAsync(context))
 463            if (SecurityServiceDispatcher.SessionMode) // for SCT, sessiontoken is created so we channel the call to Sec
 464            {
 465                IServiceChannelDispatcher serviceChannelDispatcher =
 466                   await SecurityServiceDispatcher.GetAuthChannelDispatcher(this);
 467                await serviceChannelDispatcher.DispatchAsync(securedMessage);
 468            }
 469            else
 470            {
 471                    IServiceChannelDispatcher serviceChannelDispatcher =
 472                    await SecurityServiceDispatcher.GetInnerServiceChannelDispatcher(this);
 473                    await serviceChannelDispatcher.DispatchAsync(securedMessage);
 474            }
 475        }
 476
 477        public override Task DispatchAsync(Message message)
 478        {
 479            return Task.FromException(new NotImplementedException());
 480        }
 481
 482        public void Abort()
 483        {
 484            throw new NotImplementedException();
 485        }
 486
 487        public Task CloseAsync()
 488        {
 489            throw new NotImplementedException();
 490        }
 491
 492        public Task CloseAsync(CancellationToken token)
 493        {
 494            throw new NotImplementedException();
 495        }
 496
 497        public Task OpenAsync()
 498        {
 499            return Task.CompletedTask;
 500        }
 501
 502        public Task OpenAsync(CancellationToken token)
 503        {
 504            return Task.CompletedTask;
 505        }
 506    }
 507
 508    internal abstract class SecurityDuplexChannel<UChannel> : ServerSecurityChannelDispatcher<UChannel> where UChannel :
 509    {
 510        private readonly IServiceProvider _serviceProvider;
 511        public SecurityDuplexChannel(SecurityServiceDispatcher serviceDispatcher, UChannel innerChannel, SecurityProtoco
 512          : base(serviceDispatcher, innerChannel, securityProtocol, settingsLifetimeManager)
 513        {
 514            InnerDuplexChannel = innerChannel;
 515            SecurityProtocol = securityProtocol;
 516            _serviceProvider = InnerDuplexChannel.GetProperty<IServiceScopeFactory>().CreateScope().ServiceProvider;
 517        }
 518
 519        public EndpointAddress RemoteAddress
 520        {
 521            get { return InnerDuplexChannel.RemoteAddress; }
 522        }
 523
 524        public Uri Via
 525        {
 526            get { return InnerDuplexChannel.Via; }
 527        }
 528
 529        protected IDuplexChannel InnerDuplexChannel { get; }
 530
 531        public Task SendAsync(Message message, TimeSpan timeout)
 532        {
 533            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 534            message = SecurityProtocol.SecureOutgoingMessage(message, timeoutHelper.GetCancellationToken());
 535            return InnerDuplexChannel.SendAsync(message, timeoutHelper.GetCancellationToken());
 536        }
 537    }
 538
 539    internal sealed class SecurityDuplexSessionChannelDispatcher : SecurityDuplexChannel<IDuplexSessionChannel>, IDuplex
 540    {
 541        private bool _sendUnsecuredFaults;
 542        private IServiceChannelDispatcher _serviceChannelDispatcher;
 543        public SecurityDuplexSessionChannelDispatcher(SecurityServiceDispatcher serviceDispatcher, IDuplexSessionChannel
 3544            : base(serviceDispatcher, innerChannel, securityProtocol, settingsLifetimeManager)
 545        {
 3546            _sendUnsecuredFaults = serviceDispatcher.SendUnsecuredFaults;
 3547            SecurityServiceDispatcher = serviceDispatcher;
 3548        }
 549
 550        public IDuplexSession Session
 551        {
 0552            get { return ((IDuplexSessionChannel)InnerDuplexChannel).Session; }
 553        }
 554
 0555        public EndpointAddress LocalAddress => throw new NotImplementedException();
 556
 0557        public IServiceChannelDispatcher ChannelDispatcher { get; set; }
 558
 3559        public SecurityServiceDispatcher SecurityServiceDispatcher { get; }
 560
 7561        public CommunicationState State => InnerDuplexChannel.State;
 562
 563#pragma warning disable CS0067 // The event is never used
 564        public event EventHandler Closing;
 565        public event EventHandler Faulted;
 566        public event EventHandler Opened;
 567        public event EventHandler Opening;
 568        public event EventHandler Closed;
 569#pragma warning restore CS0067 // The event is never used
 570
 571        public void Abort()
 572        {
 0573            return;
 574        }
 575
 576        public async Task CloseAsync()
 577        {
 3578            await InnerDuplexChannel.CloseAsync();
 2579        }
 580
 581        public Task CloseAsync(CancellationToken token)
 582        {
 2583            return CloseAsync();
 584        }
 585
 586        public Task OpenAsync()
 587        {
 3588            return Task.CompletedTask;
 589        }
 590
 591        public Task OpenAsync(CancellationToken token)
 592        {
 0593            return OpenAsync();
 594        }
 595
 596        public override Task DispatchAsync(RequestContext context)
 597        {
 0598            return DispatchAsync(context.RequestMessage);
 599        }
 600
 601        public override async Task DispatchAsync(Message message)
 602        {
 603            Fx.Assert(State == CommunicationState.Opened, "Expected dispatcher state to be Opened, instead it's " + Stat
 5604            message = await ProcessInnerItemAsync(message, ServiceDefaults.SendTimeout);
 5605            if (_serviceChannelDispatcher == null)
 606            {
 3607                _serviceChannelDispatcher = await SecurityServiceDispatcher.
 3608                 SecurityAuthServiceDispatcher.CreateServiceChannelDispatcherAsync(this);
 609            }
 5610            await _serviceChannelDispatcher.DispatchAsync(message);
 5611        }
 612
 613        public Task SendAsync(Message message)
 614        {
 2615            return base.SendAsync(message, ServiceDefaults.SendTimeout);
 616        }
 617
 618        public Task SendAsync(Message message, CancellationToken token)
 619        {
 2620            return SendAsync(message);
 621        }
 622
 623        private async ValueTask<Message> ProcessInnerItemAsync(Message innerItem, TimeSpan timeout)
 624        {
 5625            if (innerItem == null)
 626            {
 2627                return null;
 628            }
 3629            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 3630            Exception securityException = null;
 3631            Message unverifiedMessage = innerItem;
 632            try
 633            {
 3634                innerItem = await VerifyIncomingMessageAsync(innerItem, timeout);
 2635            }
 1636            catch (MessageSecurityException e)
 637            {
 1638                securityException = e;
 1639            }
 3640            if (securityException != null)
 641            {
 1642                await SendFaultIfRequiredAsync(securityException, unverifiedMessage, timeoutHelper.RemainingTime());
 1643                return null;
 644            }
 2645            return innerItem;
 5646        }
 647
 648        private async Task SendFaultIfRequiredAsync(Exception e, Message unverifiedMessage, TimeSpan timeout)
 649        {
 1650            if (!_sendUnsecuredFaults)
 651            {
 0652                return;
 653            }
 1654            MessageFault fault = SecurityUtils.CreateSecurityMessageFault(e, SecurityProtocol.SecurityProtocolFactory.St
 1655            if (fault == null)
 656            {
 0657                return;
 658            }
 659            try
 660            {
 1661                using (Message faultMessage = Message.CreateMessage(unverifiedMessage.Version, fault, unverifiedMessage.
 662                {
 1663                    if (unverifiedMessage.Headers.MessageId != null)
 1664                        faultMessage.InitializeReply(unverifiedMessage);
 1665                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 1666                    await ((IDuplexChannel)InnerDuplexChannel).SendAsync(faultMessage);
 1667                }
 1668            }
 669            catch (Exception ex)
 670            {
 0671                if (Fx.IsFatal(ex))
 0672                    throw;
 0673            }
 1674        }
 675
 0676        public Task<(Message message, bool success)> TryReceiveAsync(CancellationToken token) => throw new NotImplemente
 0677        public Task<Message> ReceiveAsync(CancellationToken token) => throw new NotImplementedException();
 678    }
 679
 680    internal sealed class SecurityRequestContext : RequestContextBase
 681    {
 682        private readonly RequestContext _innerContext;
 683        private readonly SecurityProtocol _securityProtocol;
 684        private readonly SecurityProtocolCorrelationState _correlationState;
 685
 686        public SecurityRequestContext(Message requestMessage, RequestContext innerContext,
 687            SecurityProtocol securityProtocol, SecurityProtocolCorrelationState correlationState,
 688            TimeSpan defaultSendTimeout, TimeSpan defaultCloseTimeout)
 689            : base(requestMessage, defaultCloseTimeout, defaultSendTimeout)
 690        {
 691            _innerContext = innerContext;
 692            _securityProtocol = securityProtocol;
 693            _correlationState = correlationState;
 694        }
 695
 696        protected override void OnAbort()
 697        {
 698            _innerContext.Abort();
 699        }
 700
 701        protected override Task OnCloseAsync(CancellationToken token)
 702        {
 703            return _innerContext.CloseAsync(token);
 704        }
 705
 706        protected override Task OnReplyAsync(Message message, CancellationToken token)
 707        {
 708            if (message != null)
 709            {
 710                (_, message) = _securityProtocol.SecureOutgoingMessage(message, _correlationState, token);
 711                return _innerContext.ReplyAsync(message, token);
 712            }
 713            else
 714            {
 715                return Task.CompletedTask;
 716            }
 717        }
 718    }
 719}