Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Security / SecuritySessionServerSettings.cs / 1 / SecuritySessionServerSettings.cs
//---------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------- namespace System.ServiceModel.Security { using System.Diagnostics; using System.Xml; using System.ServiceModel; using System.ServiceModel.Dispatcher; using System.ServiceModel.Description; using System.ServiceModel.Diagnostics; using System.Collections.Generic; using System.ServiceModel.Channels; using System.IdentityModel.Selectors; using System.IdentityModel.Claims; using System.IdentityModel.Policy; using System.IdentityModel.Tokens; using System.Runtime.Serialization; using System.Runtime.InteropServices; using System.ServiceModel.Security.Tokens; using System.Threading; // Please use 'sdv //depot/devdiv/private/indigo_xws/ndp/indigo/src/ServiceModel/System/ServiceModel/Security/SecuritySessionListenerFactory.cs' // to see version history before the file was renamed // This class is named Settings since the only public APIs are for // settings; however, this class also manages all functionality // for session channels through internal APIs sealed class SecuritySessionServerSettings : IListenerSecureConversationSessionSettings, ISecurityCommunicationObject { internal const string defaultKeyRenewalIntervalString = "15:00:00"; internal const string defaultKeyRolloverIntervalString = "00:05:00"; internal const string defaultInactivityTimeoutString = "00:02:00"; internal static readonly TimeSpan defaultKeyRenewalInterval = TimeSpan.Parse(defaultKeyRenewalIntervalString); internal static readonly TimeSpan defaultKeyRolloverInterval = TimeSpan.Parse(defaultKeyRolloverIntervalString); internal const bool defaultTolerateTransportFailures = true; internal const int defaultMaximumPendingSessions = 128; internal static readonly TimeSpan defaultInactivityTimeout = TimeSpan.Parse(defaultInactivityTimeoutString); int maximumPendingSessions; DictionarypendingSessions1; Dictionary pendingSessions2; IOThreadTimer inactivityTimer; TimeSpan inactivityTimeout; bool tolerateTransportFailures; TimeSpan maximumKeyRenewalInterval; TimeSpan keyRolloverInterval; int maximumPendingKeysPerSession; SecurityProtocolFactory sessionProtocolFactory; ICommunicationObject channelAcceptor; Dictionary activeSessions; ChannelListenerBase securityChannelListener; ChannelBuilder channelBuilder; SecurityStandardsManager standardsManager; SecurityTokenParameters issuedTokenParameters; SecurityTokenAuthenticator sessionTokenAuthenticator; ISecurityContextSecurityTokenCache sessionTokenCache; SecurityTokenResolver sessionTokenResolver; WrapperSecurityCommunicationObject communicationObject; volatile bool acceptNewWork; MessageVersion messageVersion; TimeSpan closeTimeout; TimeSpan openTimeout; TimeSpan sendTimeout; Uri listenUri; SecurityListenerSettingsLifetimeManager settingsLifetimeManager; object thisLock = new object(); public SecuritySessionServerSettings() { activeSessions = new Dictionary (); this.maximumKeyRenewalInterval = defaultKeyRenewalInterval; this.maximumPendingKeysPerSession = 5; this.keyRolloverInterval = defaultKeyRolloverInterval; this.inactivityTimeout = defaultInactivityTimeout; this.tolerateTransportFailures = defaultTolerateTransportFailures; this.maximumPendingSessions = defaultMaximumPendingSessions; this.communicationObject = new WrapperSecurityCommunicationObject(this); } internal ChannelBuilder ChannelBuilder { get { return this.channelBuilder; } set { this.communicationObject.ThrowIfDisposedOrImmutable(); this.channelBuilder = value; } } internal SecurityListenerSettingsLifetimeManager SettingsLifetimeManager { get { return this.settingsLifetimeManager; } set { this.communicationObject.ThrowIfDisposedOrImmutable(); this.settingsLifetimeManager = value; } } internal ChannelListenerBase SecurityChannelListener { get { return this.securityChannelListener; } set { this.communicationObject.ThrowIfDisposedOrImmutable(); this.securityChannelListener = value; } } Uri Uri { get { this.communicationObject.ThrowIfNotOpened(); return this.listenUri; } } object ThisLock { get { return this.thisLock; } } public SecurityTokenAuthenticator SessionTokenAuthenticator { get { return this.sessionTokenAuthenticator; } } public ISecurityContextSecurityTokenCache SessionTokenCache { get { return this.sessionTokenCache; } } public SecurityTokenResolver SessionTokenResolver { get { return this.sessionTokenResolver; } } public SecurityTokenParameters IssuedSecurityTokenParameters { get { return this.issuedTokenParameters; } set { this.communicationObject.ThrowIfDisposedOrImmutable(); this.issuedTokenParameters = value; } } public SecurityStandardsManager SecurityStandardsManager { get { return this.standardsManager; } set { this.communicationObject.ThrowIfDisposedOrImmutable(); this.standardsManager = value; } } public bool TolerateTransportFailures { get { return this.tolerateTransportFailures; } set { this.communicationObject.ThrowIfDisposedOrImmutable(); this.tolerateTransportFailures = value; } } public int MaximumPendingSessions { get { return this.maximumPendingSessions; } set { if (value <= 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value")); } this.communicationObject.ThrowIfDisposedOrImmutable(); this.maximumPendingSessions = value; } } public TimeSpan InactivityTimeout { get { return this.inactivityTimeout; } set { if (value <= TimeSpan.Zero) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.TimeSpanMustbeGreaterThanTimeSpanZero))); } this.communicationObject.ThrowIfDisposedOrImmutable(); this.inactivityTimeout = value; } } public TimeSpan MaximumKeyRenewalInterval { get { return this.maximumKeyRenewalInterval; } set { if (value <= TimeSpan.Zero) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.TimeSpanMustbeGreaterThanTimeSpanZero))); } this.communicationObject.ThrowIfDisposedOrImmutable(); this.maximumKeyRenewalInterval = value; } } public TimeSpan KeyRolloverInterval { get { return this.keyRolloverInterval; } set { if (value <= TimeSpan.Zero) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.TimeSpanMustbeGreaterThanTimeSpanZero))); } this.communicationObject.ThrowIfDisposedOrImmutable(); this.keyRolloverInterval = value; } } public int MaximumPendingKeysPerSession { get { return this.maximumPendingKeysPerSession; } set { if (value <= 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.ValueMustBeGreaterThanZero))); } this.communicationObject.ThrowIfDisposedOrImmutable(); this.maximumPendingKeysPerSession = value; } } public SecurityProtocolFactory SessionProtocolFactory { get { return this.sessionProtocolFactory; } set { this.communicationObject.ThrowIfDisposedOrImmutable(); this.sessionProtocolFactory = value; } } public MessageVersion MessageVersion { get { return this.messageVersion; } } public TimeSpan OpenTimeout { get { return this.openTimeout; } } public TimeSpan CloseTimeout { get { return this.closeTimeout; } } public TimeSpan SendTimeout { get { return this.sendTimeout; } } // ISecurityCommunicationObject members public TimeSpan DefaultOpenTimeout { get { return ServiceDefaults.OpenTimeout; } } public TimeSpan DefaultCloseTimeout { get { return ServiceDefaults.CloseTimeout; } } public IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) { return new OperationWithTimeoutAsyncResult(new OperationWithTimeoutCallback(this.OnClose), timeout, callback, state); } public IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) { return new OperationWithTimeoutAsyncResult(new OperationWithTimeoutCallback(this.OnOpen), timeout, callback, state); } public void OnClosed() { } public void OnClosing() { } public void OnEndClose(IAsyncResult result) { OperationWithTimeoutAsyncResult.End(result); } public void OnEndOpen(IAsyncResult result) { OperationWithTimeoutAsyncResult.End(result); } public void OnFaulted() { } public void OnOpened() { } public void OnOpening() { } public void OnAbort() { this.AbortPendingChannels(); this.OnAbortCore(); } public void OnClose(TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); this.ClosePendingChannels(timeoutHelper.RemainingTime()); this.OnCloseCore(timeoutHelper.RemainingTime()); } internal void Close(TimeSpan timeout) { this.communicationObject.Close(timeout); } internal IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state) { return this.communicationObject.BeginClose(timeout, callback, state); } internal void EndClose(IAsyncResult result) { this.communicationObject.EndClose(result); } internal void Abort() { this.communicationObject.Abort(); } internal void Open(TimeSpan timeout) { this.communicationObject.Open(timeout); } internal IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state) { return this.communicationObject.BeginOpen(timeout, callback, state); } internal void EndOpen(IAsyncResult result) { this.communicationObject.EndOpen(result); } void OnCloseCore(TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); if (this.inactivityTimer != null) { this.inactivityTimer.Cancel(); } if (this.sessionProtocolFactory != null) { this.sessionProtocolFactory.Close(false, timeoutHelper.RemainingTime()); } if (this.sessionTokenAuthenticator != null) { SecurityUtils.CloseTokenAuthenticatorIfRequired(this.sessionTokenAuthenticator, timeoutHelper.RemainingTime()); } } void OnAbortCore() { if (this.inactivityTimer != null) { this.inactivityTimer.Cancel(); } if (this.sessionProtocolFactory != null) { this.sessionProtocolFactory.Close(true, TimeSpan.Zero); } if (this.sessionTokenAuthenticator != null) { SecurityUtils.AbortTokenAuthenticatorIfRequired(this.sessionTokenAuthenticator); } } void SetupSessionTokenAuthenticator() { RecipientServiceModelSecurityTokenRequirement requirement = new RecipientServiceModelSecurityTokenRequirement(); this.issuedTokenParameters.InitializeSecurityTokenRequirement(requirement); requirement.KeyUsage = SecurityKeyUsage.Signature; requirement.ListenUri = this.listenUri; requirement.SecurityBindingElement = this.sessionProtocolFactory.SecurityBindingElement; requirement.SecurityAlgorithmSuite = this.sessionProtocolFactory.IncomingAlgorithmSuite; requirement.SupportSecurityContextCancellation = true; requirement.MessageSecurityVersion = sessionProtocolFactory.MessageSecurityVersion.SecurityTokenVersion; requirement.AuditLogLocation = sessionProtocolFactory.AuditLogLocation; requirement.SuppressAuditFailure = sessionProtocolFactory.SuppressAuditFailure; requirement.MessageAuthenticationAuditLevel = sessionProtocolFactory.MessageAuthenticationAuditLevel; requirement.Properties[ServiceModelSecurityTokenRequirement.MessageDirectionProperty] = MessageDirection.Input; if (sessionProtocolFactory.EndpointFilterTable != null) { requirement.Properties[ServiceModelSecurityTokenRequirement.EndpointFilterTableProperty] = sessionProtocolFactory.EndpointFilterTable; } this.sessionTokenAuthenticator = this.sessionProtocolFactory.SecurityTokenManager.CreateSecurityTokenAuthenticator(requirement, out this.sessionTokenResolver); if (!(this.sessionTokenAuthenticator is IIssuanceSecurityTokenAuthenticator)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecuritySessionRequiresIssuanceAuthenticator, typeof(IIssuanceSecurityTokenAuthenticator), this.sessionTokenAuthenticator.GetType()))); } if (sessionTokenResolver == null || (!(sessionTokenResolver is ISecurityContextSecurityTokenCache))) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecuritySessionRequiresSecurityContextTokenCache, this.sessionTokenResolver.GetType(), typeof(ISecurityContextSecurityTokenCache)))); } this.sessionTokenCache = (ISecurityContextSecurityTokenCache)this.sessionTokenResolver; } public void OnOpen(TimeSpan timeout) { if (this.sessionProtocolFactory == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecuritySessionProtocolFactoryShouldBeSetBeforeThisOperation))); } if (this.standardsManager == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecurityStandardsManagerNotSet, this.GetType()))); } if (this.issuedTokenParameters == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.IssuedSecurityTokenParametersNotSet, this.GetType()))); } if (this.maximumKeyRenewalInterval < this.keyRolloverInterval) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.KeyRolloverGreaterThanKeyRenewal))); } if (this.securityChannelListener == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecurityChannelListenerNotSet, this.GetType()))); } if (this.settingsLifetimeManager == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecuritySettingsLifetimeManagerNotSet, this.GetType()))); } this.messageVersion = this.channelBuilder.Binding.MessageVersion; this.listenUri = this.securityChannelListener.Uri; this.openTimeout = this.securityChannelListener.InternalOpenTimeout; this.closeTimeout = this.securityChannelListener.InternalCloseTimeout; this.sendTimeout = this.securityChannelListener.InternalSendTimeout; TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); this.pendingSessions1 = new Dictionary (); this.pendingSessions2 = new Dictionary (); if (this.inactivityTimeout < TimeSpan.MaxValue) { this.inactivityTimer = new IOThreadTimer(this.OnTimer, this, false); this.inactivityTimer.Set(this.inactivityTimeout); } this.ConfigureSessionSecurityProtocolFactory(); this.sessionProtocolFactory.Open(false, timeoutHelper.RemainingTime()); SetupSessionTokenAuthenticator(); ((IIssuanceSecurityTokenAuthenticator) this.sessionTokenAuthenticator).IssuedSecurityTokenHandler = this.OnTokenIssued; ((IIssuanceSecurityTokenAuthenticator)this.sessionTokenAuthenticator).RenewedSecurityTokenHandler = this.OnTokenRenewed; this.acceptNewWork = true; SecurityUtils.OpenTokenAuthenticatorIfRequired(this.sessionTokenAuthenticator, timeoutHelper.RemainingTime()); } public void StopAcceptingNewWork() { this.acceptNewWork = false; } int GetPendingSessionCount() { return this.pendingSessions1.Count + this.pendingSessions2.Count + ((IInputQueueChannelAcceptor)this.channelAcceptor).PendingCount; } void AbortPendingChannels() { lock (ThisLock) { if (this.pendingSessions1 != null) { foreach (IServerReliableChannelBinder pendingChannelBinder in pendingSessions1.Values) { pendingChannelBinder.Abort(); } } if (this.pendingSessions2 != null) { foreach (IServerReliableChannelBinder pendingChannelBinder in pendingSessions2.Values) { pendingChannelBinder.Abort(); } } } } void ClosePendingChannels(TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); lock (ThisLock) { foreach (IServerReliableChannelBinder pendingChannelBinder in pendingSessions1.Values) { pendingChannelBinder.Close(timeoutHelper.RemainingTime()); } foreach (IServerReliableChannelBinder pendingChannelBinder in pendingSessions2.Values) { pendingChannelBinder.Close(timeoutHelper.RemainingTime()); } } } void ConfigureSessionSecurityProtocolFactory() { if (this.sessionProtocolFactory is SessionSymmetricMessageSecurityProtocolFactory) { AddressingVersion addressing = MessageVersion.Default.Addressing; if (this.channelBuilder != null) { MessageEncodingBindingElement encoding = this.channelBuilder.Binding.Elements.Find (); if (encoding != null) { addressing = encoding.MessageVersion.Addressing; } } if (addressing != AddressingVersion.WSAddressing10 && addressing != AddressingVersion.WSAddressingAugust2004) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ProtocolException(SR.GetString(SR.AddressingVersionNotSupported, addressing))); } SessionSymmetricMessageSecurityProtocolFactory messagePf = (SessionSymmetricMessageSecurityProtocolFactory)this.sessionProtocolFactory; if (!messagePf.ApplyIntegrity || !messagePf.RequireIntegrity) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecuritySessionRequiresMessageIntegrity))); } MessagePartSpecification bodyPart = new MessagePartSpecification(true); messagePf.ProtectionRequirements.IncomingSignatureParts.AddParts(bodyPart, this.SecurityStandardsManager.SecureConversationDriver.CloseAction); messagePf.ProtectionRequirements.IncomingSignatureParts.AddParts(bodyPart, this.SecurityStandardsManager.SecureConversationDriver.CloseResponseAction); messagePf.ProtectionRequirements.OutgoingSignatureParts.AddParts(bodyPart, this.SecurityStandardsManager.SecureConversationDriver.CloseResponseAction); messagePf.ProtectionRequirements.OutgoingSignatureParts.AddParts(bodyPart, this.SecurityStandardsManager.SecureConversationDriver.CloseAction); messagePf.ProtectionRequirements.OutgoingSignatureParts.AddParts(bodyPart, addressing.FaultAction); messagePf.ProtectionRequirements.OutgoingSignatureParts.AddParts(bodyPart, addressing.DefaultFaultAction); messagePf.ProtectionRequirements.OutgoingSignatureParts.AddParts(bodyPart, DotNetSecurityStrings.SecuritySessionFaultAction); if (messagePf.ApplyConfidentiality) { messagePf.ProtectionRequirements.OutgoingEncryptionParts.AddParts(MessagePartSpecification.NoParts, this.SecurityStandardsManager.SecureConversationDriver.CloseResponseAction); messagePf.ProtectionRequirements.OutgoingEncryptionParts.AddParts(MessagePartSpecification.NoParts, this.SecurityStandardsManager.SecureConversationDriver.CloseAction); messagePf.ProtectionRequirements.OutgoingEncryptionParts.AddParts(bodyPart, addressing.FaultAction); messagePf.ProtectionRequirements.OutgoingEncryptionParts.AddParts(bodyPart, addressing.DefaultFaultAction); messagePf.ProtectionRequirements.OutgoingEncryptionParts.AddParts(bodyPart, DotNetSecurityStrings.SecuritySessionFaultAction); } if (messagePf.RequireConfidentiality) { messagePf.ProtectionRequirements.IncomingEncryptionParts.AddParts(MessagePartSpecification.NoParts, this.SecurityStandardsManager.SecureConversationDriver.CloseAction); messagePf.ProtectionRequirements.IncomingEncryptionParts.AddParts(MessagePartSpecification.NoParts, this.SecurityStandardsManager.SecureConversationDriver.CloseResponseAction); } messagePf.SecurityTokenParameters = this.IssuedSecurityTokenParameters; } else if (this.sessionProtocolFactory is SessionSymmetricTransportSecurityProtocolFactory) { SessionSymmetricTransportSecurityProtocolFactory transportPf = (SessionSymmetricTransportSecurityProtocolFactory)this.sessionProtocolFactory; transportPf.AddTimestamp = true; transportPf.SecurityTokenParameters = this.IssuedSecurityTokenParameters; transportPf.SecurityTokenParameters.RequireDerivedKeys = false; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } } internal IChannelAcceptor CreateAcceptor () where TChannel : class, IChannel { if (this.channelAcceptor != null) { DiagnosticUtility.DebugAssert("SecuritySessionServerSettings.CreateAcceptor (this.channelAcceptor != null)"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SSSSCreateAcceptor))); } object listenerSecurityState = this.sessionProtocolFactory.CreateListenerSecurityState(); if (typeof(TChannel) == typeof(IReplySessionChannel)) { this.channelAcceptor = new SecuritySessionChannelAcceptor (this.SecurityChannelListener, listenerSecurityState); } else if (typeof(TChannel) == typeof(IDuplexSessionChannel)) { this.channelAcceptor = new SecuritySessionChannelAcceptor (this.SecurityChannelListener, listenerSecurityState); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } return (IChannelAcceptor )this.channelAcceptor; } internal IChannelListener CreateInnerChannelListener() { if (this.ChannelBuilder.CanBuildChannelListener ()) { return this.ChannelBuilder.BuildChannelListener (new MatchNoneMessageFilter(), int.MinValue); } else if (this.ChannelBuilder.CanBuildChannelListener ()) { return this.ChannelBuilder.BuildChannelListener (new MatchNoneMessageFilter(), int.MinValue); } else if (this.ChannelBuilder.CanBuildChannelListener ()) { return this.ChannelBuilder.BuildChannelListener (new MatchNoneMessageFilter(), int.MinValue); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } } void OnTokenRenewed(SecurityToken newToken, SecurityToken oldToken) { this.communicationObject.ThrowIfClosed(); if (!this.acceptNewWork) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(SR.SecurityListenerClosing))); } SecurityContextSecurityToken newSecurityContextToken = newToken as SecurityContextSecurityToken; if (newSecurityContextToken == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SessionTokenIsNotSecurityContextToken, newToken.GetType(), typeof(SecurityContextSecurityToken)))); } SecurityContextSecurityToken oldSecurityContextToken = oldToken as SecurityContextSecurityToken; if (oldSecurityContextToken == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SessionTokenIsNotSecurityContextToken, oldToken.GetType(), typeof(SecurityContextSecurityToken)))); } IServerSecuritySessionChannel sessionChannel = this.FindSessionChannel(newSecurityContextToken.ContextId); if (sessionChannel == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.CannotFindSecuritySession, newSecurityContextToken.ContextId))); } sessionChannel.RenewSessionToken(newSecurityContextToken, oldSecurityContextToken); } IServerReliableChannelBinder CreateChannelBinder(SecurityContextSecurityToken sessionToken, EndpointAddress remoteAddress) { IServerReliableChannelBinder result = null; MessageFilter sctFilter = new SecuritySessionFilter(sessionToken.ContextId, this.sessionProtocolFactory.StandardsManager, (this.sessionProtocolFactory.SecurityHeaderLayout == SecurityHeaderLayout.Strict), this.SecurityStandardsManager.SecureConversationDriver.RenewAction.Value, this.SecurityStandardsManager.SecureConversationDriver.RenewResponseAction.Value); int sctPriority = Int32.MaxValue; TolerateFaultsMode faultMode = this.TolerateTransportFailures ? TolerateFaultsMode.Always : TolerateFaultsMode.Never; lock (ThisLock) { if (this.ChannelBuilder.CanBuildChannelListener ()) { result = ServerReliableChannelBinder .CreateBinder(this.ChannelBuilder, remoteAddress, sctFilter, sctPriority, faultMode, this.CloseTimeout, this.SendTimeout); } else if (this.ChannelBuilder.CanBuildChannelListener ()) { result = ServerReliableChannelBinder .CreateBinder(this.ChannelBuilder, remoteAddress, sctFilter, sctPriority, faultMode, this.CloseTimeout, this.SendTimeout); } else if (this.ChannelBuilder.CanBuildChannelListener ()) { result = ServerReliableChannelBinder .CreateBinder(this.ChannelBuilder, remoteAddress, sctFilter, sctPriority, faultMode, this.CloseTimeout, this.SendTimeout); } } if (result == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } result.Open(this.OpenTimeout); SessionInitiationMessageHandler handler = new SessionInitiationMessageHandler(result, this, sessionToken); handler.BeginReceive(TimeoutHelper.Infinite); return result; } void OnTokenIssued(SecurityToken issuedToken, EndpointAddress tokenRequestor) { this.communicationObject.ThrowIfClosed(); if (!this.acceptNewWork) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(SR.SecurityListenerClosing))); } SecurityContextSecurityToken issuedSecurityContextToken = issuedToken as SecurityContextSecurityToken; if (issuedSecurityContextToken == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SessionTokenIsNotSecurityContextToken, issuedToken.GetType(), typeof(SecurityContextSecurityToken)))); } IServerReliableChannelBinder channelBinder = CreateChannelBinder(issuedSecurityContextToken, tokenRequestor ?? EndpointAddress.AnonymousAddress); bool wasSessionAdded = false; try { this.AddPendingSession(issuedSecurityContextToken.ContextId, channelBinder); wasSessionAdded = true; } finally { if (!wasSessionAdded) { channelBinder.Abort(); } } } void OnTimer(object state) { if (this.communicationObject.State == CommunicationState.Closed || this.communicationObject.State == CommunicationState.Faulted) { return; } try { this.ClearPendingSessions(); } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) throw; } finally { if (this.communicationObject.State != CommunicationState.Closed && this.communicationObject.State != CommunicationState.Closing && this.communicationObject.State != CommunicationState.Faulted) { this.inactivityTimer.Set(this.inactivityTimeout); } } } void AddPendingSession(UniqueId sessionId, IServerReliableChannelBinder channelBinder) { lock (ThisLock) { if ((GetPendingSessionCount() + 1) > this.MaximumPendingSessions) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QuotaExceededException(SR.GetString(SR.SecuritySessionLimitReached))); } if (this.pendingSessions1.ContainsKey(sessionId) || this.pendingSessions2.ContainsKey(sessionId)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SecuritySessionAlreadyPending, sessionId))); } this.pendingSessions1.Add(sessionId, channelBinder); } SecurityTraceRecordHelper.TracePendingSessionAdded(sessionId, this.Uri); } void TryCloseBinder(IServerReliableChannelBinder binder, TimeSpan timeout) { bool abortBinder = false; try { binder.Close(timeout); } catch (CommunicationException e) { abortBinder = true; if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } } catch (TimeoutException e) { abortBinder = true; if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } } finally { if (abortBinder) { binder.Abort(); } } } // this method should be called by the timer under ThisLock void ClearPendingSessions() { lock (ThisLock) { if (this.pendingSessions1.Count == 0 && this.pendingSessions2.Count == 0) { return; } foreach (UniqueId sessionId in this.pendingSessions2.Keys) { IServerReliableChannelBinder channelBinder = this.pendingSessions2[sessionId]; try { TryCloseBinder(channelBinder, this.CloseTimeout); this.SessionTokenCache.RemoveAllContexts(sessionId); } catch (CommunicationException e) { if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } } catch (TimeoutException e) { if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } } catch (ObjectDisposedException e) { if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } } SecurityTraceRecordHelper.TracePendingSessionClosed(sessionId, this.Uri); } this.pendingSessions2.Clear(); Dictionary temp = this.pendingSessions2; this.pendingSessions2 = this.pendingSessions1; this.pendingSessions1 = temp; } } bool RemovePendingSession(UniqueId sessionId) { bool result; lock (ThisLock) { if (this.pendingSessions1.ContainsKey(sessionId)) { this.pendingSessions1.Remove(sessionId); result = true; } else if (pendingSessions2.ContainsKey(sessionId)) { this.pendingSessions2.Remove(sessionId); result = true; } else { result = false; } } if (result) { SecurityTraceRecordHelper.TracePendingSessionActivated(sessionId, this.Uri); } return result; } IServerSecuritySessionChannel FindSessionChannel(UniqueId sessionId) { IServerSecuritySessionChannel result; lock (ThisLock) { this.activeSessions.TryGetValue(sessionId, out result); } return result; } void AddSessionChannel(UniqueId sessionId, IServerSecuritySessionChannel channel) { lock (ThisLock) { this.activeSessions.Add(sessionId, channel); } } void RemoveSessionChannel(string sessionId) { RemoveSessionChannel(new UniqueId(sessionId)); } void RemoveSessionChannel(UniqueId sessionId) { lock (ThisLock) { this.activeSessions.Remove(sessionId); } SecurityTraceRecordHelper.TraceActiveSessionRemoved(sessionId, this.Uri); } class SessionInitiationMessageHandler { static AsyncCallback receiveCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(ReceiveCallback)); IServerReliableChannelBinder channelBinder; SecuritySessionServerSettings settings; SecurityContextSecurityToken sessionToken; bool processedInitiation = false; public SessionInitiationMessageHandler(IServerReliableChannelBinder channelBinder, SecuritySessionServerSettings settings, SecurityContextSecurityToken sessionToken) { this.channelBinder = channelBinder; this.settings = settings; this.sessionToken = sessionToken; } public IAsyncResult BeginReceive(TimeSpan timeout) { return this.channelBinder.BeginTryReceive(timeout, receiveCallback, this); } bool IsRecoverableException(Exception e) { // this can be thrown at close time when another thread tries to abort the underlying // binder. It can be ignored return ((e is ObjectDisposedException) || (e is CommunicationException) || (e is TimeoutException) || (e is QuotaExceededException) || (e is InvalidOperationException) || (e is XmlException) || (e is FormatException)); } public void ProcessMessage(IAsyncResult result) { bool threwException = false; try { RequestContext requestContext; if (!this.channelBinder.EndTryReceive(result, out requestContext)) { // we should never have timed out since the receive was called with an Infinite timeout // if we did then do a BeginReceive and return this.BeginReceive(TimeoutHelper.Infinite); return; } if (requestContext == null) { return; } Message message = requestContext.RequestMessage; lock (this.settings.ThisLock) { if (this.settings.communicationObject.State != CommunicationState.Opened) { ((IDisposable)requestContext).Dispose(); return; } if (this.processedInitiation) { return; } this.processedInitiation = true; } if (!this.settings.RemovePendingSession(this.sessionToken.ContextId)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new CommunicationException(SR.GetString(SR.SecuritySessionNotPending, this.sessionToken.ContextId))); } if (this.settings.channelAcceptor is SecuritySessionChannelAcceptor ) { SecuritySessionChannelAcceptor replyAcceptor = ((SecuritySessionChannelAcceptor )this.settings.channelAcceptor); SecurityReplySessionChannel replySessionChannel = new SecurityReplySessionChannel(this.settings, this.channelBinder, sessionToken, replyAcceptor.ListenerSecurityState, this.settings.SettingsLifetimeManager); settings.AddSessionChannel(this.sessionToken.ContextId, replySessionChannel); replySessionChannel.StartReceiving(requestContext); replyAcceptor.EnqueueAndDispatch(replySessionChannel); } else if (this.settings.channelAcceptor is SecuritySessionChannelAcceptor ) { SecuritySessionChannelAcceptor duplexAcceptor = ((SecuritySessionChannelAcceptor )this.settings.channelAcceptor); ServerSecurityDuplexSessionChannel duplexSessionChannel = new ServerSecurityDuplexSessionChannel(this.settings, this.channelBinder, sessionToken, duplexAcceptor.ListenerSecurityState, this.settings.SettingsLifetimeManager); settings.AddSessionChannel(this.sessionToken.ContextId, duplexSessionChannel); duplexSessionChannel.StartReceiving(requestContext); duplexAcceptor.EnqueueAndDispatch(duplexSessionChannel); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new EndpointNotFoundException(SR.GetString(SR.SecuritySessionListenerNotFound, message.Headers.Action))); } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { threwException = true; if (!IsRecoverableException(e)) { throw; } } finally { if (threwException) { this.channelBinder.Abort(); } } } static void ReceiveCallback(IAsyncResult result) { ((SessionInitiationMessageHandler)result.AsyncState).ProcessMessage(result); } } interface IInputQueueChannelAcceptor { int PendingCount { get; } } class SecuritySessionChannelAcceptor : InputQueueChannelAcceptor , IInputQueueChannelAcceptor where T : class, IChannel { object listenerState; public SecuritySessionChannelAcceptor(ChannelListenerBase manager, object listenerState) : base(manager) { this.listenerState = listenerState; } public object ListenerSecurityState { get { return this.listenerState; } } int IInputQueueChannelAcceptor.PendingCount { get { return this.PendingCount; } } } interface IServerSecuritySessionChannel { void RenewSessionToken(SecurityContextSecurityToken newToken, SecurityContextSecurityToken supportingToken); } abstract class ServerSecuritySessionChannel : ChannelBase, IServerSecuritySessionChannel { FaultCode renewFaultCode; FaultReason renewFaultReason; FaultCode sessionAbortedFaultCode; FaultReason sessionAbortedFaultReason; volatile bool areFaultCodesInitialized; IServerReliableChannelBinder channelBinder; SecurityProtocol securityProtocol; // This is used to sign outgoing messages SecurityContextSecurityToken currentSessionToken; UniqueId sessionId; // These are renewed tokens that have not been used as yet List futureSessionTokens; SecuritySessionServerSettings settings; RequestContext initialRequestContext; volatile bool isInputClosed; ThreadNeutralSemaphore receiveLock = new ThreadNeutralSemaphore(1); MessageVersion messageVersion; SecurityListenerSettingsLifetimeManager settingsLifetimeManager; volatile bool hasSecurityStateReference; protected ServerSecuritySessionChannel(SecuritySessionServerSettings settings, IServerReliableChannelBinder channelBinder, SecurityContextSecurityToken sessionToken, object listenerSecurityProtocolState, SecurityListenerSettingsLifetimeManager settingsLifetimeManager) : base(settings.SecurityChannelListener) { this.settings = settings; this.channelBinder = channelBinder; this.messageVersion = settings.MessageVersion; this.channelBinder.Faulted += this.OnInnerFaulted; this.securityProtocol = this.Settings.SessionProtocolFactory.CreateSecurityProtocol(null, null, listenerSecurityProtocolState, true, TimeSpan.Zero); if (!(this.securityProtocol is IAcceptorSecuritySessionProtocol)) { DiagnosticUtility.DebugAssert("Security protocol must be IAcceptorSecuritySessionProtocol."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ProtocolMisMatch, "IAcceptorSecuritySessionProtocol", this.GetType().ToString()))); } this.currentSessionToken = sessionToken; this.sessionId = sessionToken.ContextId; this.futureSessionTokens = new List (1); ((IAcceptorSecuritySessionProtocol) this.securityProtocol).SetOutgoingSessionToken(sessionToken); ((IAcceptorSecuritySessionProtocol)this.securityProtocol).SetSessionTokenAuthenticator(this.sessionId, this.settings.SessionTokenAuthenticator, this.settings.SessionTokenResolver); this.settingsLifetimeManager = settingsLifetimeManager; } protected SecuritySessionServerSettings Settings { get { return this.settings; } } protected virtual bool CanDoSecurityCorrelation { get { return false; } } internal IServerReliableChannelBinder ChannelBinder { get { return this.channelBinder; } } internal TimeSpan InternalSendTimeout { get { return this.DefaultSendTimeout; } } public EndpointAddress LocalAddress { get { return this.channelBinder.LocalAddress; } } protected override void OnOpen(TimeSpan timeout) { this.securityProtocol.Open(timeout); if (this.CanDoSecurityCorrelation) { ((IAcceptorSecuritySessionProtocol)this.securityProtocol).ReturnCorrelationState = true; } lock (ThisLock) { // if an abort happened concurrently with the open, then return if (this.State == CommunicationState.Closed || this.State == CommunicationState.Closing) { return; } this.settingsLifetimeManager.AddReference(); this.hasSecurityStateReference = true; } } protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) { OnOpen(timeout); return new CompletedAsyncResult(callback, state); } protected override void OnEndOpen(IAsyncResult result) { CompletedAsyncResult.End(result); } protected virtual void AbortCore() { if (this.channelBinder != null) { this.channelBinder.Abort(); } if (this.securityProtocol != null) { this.securityProtocol.Close(true, TimeSpan.Zero); } this.Settings.SessionTokenCache.RemoveAllContexts(this.currentSessionToken.ContextId); bool abortLifetimeManager = false; lock (ThisLock) { if (hasSecurityStateReference) { abortLifetimeManager = true; hasSecurityStateReference = false; } } if (abortLifetimeManager) { this.settingsLifetimeManager.Abort(); } } protected virtual void CloseCore(TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); try { if (this.channelBinder != null) { this.channelBinder.Close(timeoutHelper.RemainingTime()); } if (this.securityProtocol != null) { this.securityProtocol.Close(false, timeoutHelper.RemainingTime()); } bool closeLifetimeManager = false; lock (ThisLock) { if (hasSecurityStateReference) { closeLifetimeManager = true; hasSecurityStateReference = false; } } if (closeLifetimeManager) { this.settingsLifetimeManager.Close(timeoutHelper.RemainingTime()); } } catch (CommunicationObjectAbortedException) { if (this.State != CommunicationState.Closed) { throw; } // a parallel thread aborted the channel. Ignore the exception } this.Settings.SessionTokenCache.RemoveAllContexts(this.currentSessionToken.ContextId); } protected virtual IAsyncResult BeginCloseCore(TimeSpan timeout, AsyncCallback callback, object state) { return new CloseCoreAsyncResult(this, timeout, callback, state); } protected virtual void EndCloseCore(IAsyncResult result) { CloseCoreAsyncResult.End(result); } protected abstract void OnCloseMessageReceived(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout); protected abstract void OnCloseResponseMessageReceived(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout); public void RenewSessionToken(SecurityContextSecurityToken newToken, SecurityContextSecurityToken supportingToken) { ThrowIfClosedOrNotOpen(); // enforce that the token being renewed is the current session token lock (ThisLock) { if (supportingToken.ContextId != this.currentSessionToken.ContextId || supportingToken.KeyGeneration != this.currentSessionToken.KeyGeneration) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.CurrentSessionTokenNotRenewed, supportingToken.KeyGeneration, this.currentSessionToken.KeyGeneration))); } if (this.futureSessionTokens.Count == this.Settings.MaximumPendingKeysPerSession) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.TooManyPendingSessionKeys))); } this.futureSessionTokens.Add(newToken); } SecurityTraceRecordHelper.TraceNewServerSessionKeyIssued(newToken, supportingToken, GetLocalUri()); } protected Uri GetLocalUri() { if (this.channelBinder.LocalAddress == null) return null; else return this.channelBinder.LocalAddress.Uri; } void OnInnerFaulted(IReliableChannelBinder sender, Exception exception) { this.Fault(exception); } SecurityContextSecurityToken GetSessionToken(SecurityMessageProperty securityProperty) { SecurityContextSecurityToken sct = (securityProperty.ProtectionToken != null) ? securityProperty.ProtectionToken.SecurityToken as SecurityContextSecurityToken : null; if (sct != null && sct.ContextId == this.sessionId) { return sct; } if (securityProperty.HasIncomingSupportingTokens) { for (int i = 0; i < securityProperty.IncomingSupportingTokens.Count; ++i) { if (securityProperty.IncomingSupportingTokens[i].SecurityTokenAttachmentMode == SecurityTokenAttachmentMode.Endorsing) { sct = (securityProperty.IncomingSupportingTokens[i].SecurityToken as SecurityContextSecurityToken); if (sct != null && sct.ContextId == this.sessionId) { return sct; } } } } return null; } bool CheckIncomingToken(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout) { SecurityMessageProperty securityProperty = message.Properties.Security; // this is guaranteed to be non-null and matches the session ID since the binding checked it SecurityContextSecurityToken incomingToken = GetSessionToken(securityProperty); if (incomingToken == null) { throw TraceUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.NoSessionTokenPresentInMessage)), message); } // the incoming token's key should have been issued within keyRenewalPeriod time in the past // if not, send back a renewal fault. However if this is a session close message then its ok to not require the client // to renew the key in order to send the close. if (incomingToken.KeyExpirationTime < DateTime.UtcNow && message.Headers.Action != this.settings.SecurityStandardsManager.SecureConversationDriver.CloseAction.Value) { SendRenewFault(requestContext, correlationState, timeout); return false; } // this is a valid token. If it corresponds to a newly issued session token, make it the current // session token. lock (ThisLock) { if (this.futureSessionTokens.Count > 0 && incomingToken.KeyGeneration != this.currentSessionToken.KeyGeneration) { bool changedCurrentSessionToken = false; for (int i = 0; i < this.futureSessionTokens.Count; ++i) { if (futureSessionTokens[i].KeyGeneration == incomingToken.KeyGeneration) { // let the current token expire after KeyRollover time interval DateTime keyRolloverTime = TimeoutHelper.Add(DateTime.UtcNow, this.settings.KeyRolloverInterval); this.settings.SessionTokenCache.UpdateContextCachingTime(this.currentSessionToken, keyRolloverTime); this.currentSessionToken = futureSessionTokens[i]; futureSessionTokens.RemoveAt(i); ((IAcceptorSecuritySessionProtocol)this.securityProtocol).SetOutgoingSessionToken(this.currentSessionToken); changedCurrentSessionToken = true; break; } } if (changedCurrentSessionToken) { SecurityTraceRecordHelper.TraceServerSessionKeyUpdated(this.currentSessionToken, GetLocalUri()); // remove all renewed tokens that will never be used. for (int i = 0; i < futureSessionTokens.Count; ++i) { this.Settings.SessionTokenCache.RemoveContext(futureSessionTokens[i].ContextId, futureSessionTokens[i].KeyGeneration); } this.futureSessionTokens.Clear(); } } } return true; } public void StartReceiving(RequestContext initialRequestContext) { if (this.initialRequestContext != null) { DiagnosticUtility.DebugAssert("The initial request context was already specified."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.AttemptToCreateMultipleRequestContext))); } this.initialRequestContext = initialRequestContext; } public RequestContext ReceiveRequest() { return this.ReceiveRequest(this.DefaultReceiveTimeout); } public RequestContext ReceiveRequest(TimeSpan timeout) { RequestContext requestContext; if (this.TryReceiveRequest(timeout, out requestContext)) { return requestContext; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException()); } } public IAsyncResult BeginReceiveRequest(AsyncCallback callback, object state) { return this.BeginReceiveRequest(this.DefaultReceiveTimeout, callback, state); } public IAsyncResult BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state) { return this.BeginTryReceiveRequest(timeout, callback, state); } public RequestContext EndReceiveRequest(IAsyncResult result) { RequestContext requestContext; if (this.EndTryReceiveRequest(result, out requestContext)) { return requestContext; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException()); } } public IAsyncResult BeginTryReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state) { return new ReceiveRequestAsyncResult(this, timeout, callback, state); } public bool EndTryReceiveRequest(IAsyncResult result, out RequestContext requestContext) { return ReceiveRequestAsyncResult.EndAsRequestContext(result, out requestContext); } public bool TryReceiveRequest(TimeSpan timeout, out RequestContext requestContext) { ThrowIfFaulted(); TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); if (!receiveLock.TryEnter(timeoutHelper.RemainingTime())) { requestContext = null; return false; } try { while (true) { if (isInputClosed || this.State == CommunicationState.Faulted) { break; } // schedule another Receive if the timeout has not been reached if (timeoutHelper.RemainingTimeExpireNegative() < TimeSpan.Zero) { requestContext = null; return false; } RequestContext innerRequestContext; if (initialRequestContext != null) { innerRequestContext = initialRequestContext; initialRequestContext = null; } else { if (!channelBinder.TryReceive(timeoutHelper.RemainingTime(), out innerRequestContext)) { requestContext = null; return false; } } if (innerRequestContext == null) { // the channel could have been aborted or closed break; } if (this.isInputClosed && innerRequestContext.RequestMessage != null) { Message message = innerRequestContext.RequestMessage; try { ProtocolException error = ProtocolException.ReceiveShutdownReturnedNonNull(message); throw TraceUtility.ThrowHelperWarning(error, message); } finally { message.Close(); innerRequestContext.Abort(); } } SecurityProtocolCorrelationState correlationState = null; bool isSecurityProcessingFailure; Message requestMessage = ProcessRequestContext(innerRequestContext, timeoutHelper.RemainingTime(), out correlationState, out isSecurityProcessingFailure); if (requestMessage != null) { requestContext = new SecuritySessionRequestContext(innerRequestContext, requestMessage, correlationState, this); return true; } } } finally { receiveLock.Exit(); } ThrowIfFaulted(); requestContext = null; return true; } public Message Receive() { return this.Receive(this.DefaultReceiveTimeout); } public Message Receive(TimeSpan timeout) { Message message; if (this.TryReceive(timeout, out message)) { return message; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException()); } } public IAsyncResult BeginReceive(AsyncCallback callback, object state) { return this.BeginReceive(this.DefaultReceiveTimeout, callback, state); } public IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state) { return this.BeginTryReceive(timeout, callback, state); } public Message EndReceive(IAsyncResult result) { Message message; if (this.EndTryReceive(result, out message)) { return message; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException()); } } public IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state) { return new ReceiveRequestAsyncResult(this, timeout, callback, state); } public bool EndTryReceive(IAsyncResult result, out Message message) { return ReceiveRequestAsyncResult.EndAsMessage(result, out message); } public bool TryReceive(TimeSpan timeout, out Message message) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); RequestContext requestContext; if (this.TryReceiveRequest(timeoutHelper.RemainingTime(), out requestContext)) { if (requestContext != null) { message = requestContext.RequestMessage; try { requestContext.Close(timeoutHelper.RemainingTime()); } catch (TimeoutException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, System.Diagnostics.TraceEventType.Information); } } else { message = null; } return true; } else { message = null; return false; } } public override T GetProperty () { if (typeof(T) == typeof(FaultConverter) && (this.channelBinder != null)) { return new SecurityChannelFaultConverter(this.channelBinder.Channel) as T; } T result = base.GetProperty (); if ((result == null) && (channelBinder != null) && (channelBinder.Channel != null)) { result = channelBinder.Channel.GetProperty (); } return result; } void SendFaultIfRequired(Exception e, Message unverifiedMessage, RequestContext requestContext, TimeSpan timeout) { try { // return if the underlying channel does not implement IDuplexSession or IReply if (!(this.channelBinder.Channel is IReplyChannel) && !(this.channelBinder.Channel is IDuplexSessionChannel)) { return; } MessageFault fault = SecurityUtils.CreateSecurityMessageFault(e, this.securityProtocol.SecurityProtocolFactory.StandardsManager); if (fault == null) { return; } TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); try { using (Message faultMessage = Message.CreateMessage(unverifiedMessage.Version, fault, unverifiedMessage.Version.Addressing.DefaultFaultAction)) { if (unverifiedMessage.Headers.MessageId != null) faultMessage.InitializeReply(unverifiedMessage); requestContext.Reply(faultMessage, timeoutHelper.RemainingTime()); requestContext.Close(timeoutHelper.RemainingTime()); } } catch (CommunicationException ex) { if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.ExceptionUtility.TraceHandledException(ex, TraceEventType.Information); } } catch (TimeoutException ex) { if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.ExceptionUtility.TraceHandledException(ex, TraceEventType.Information); } } } finally { unverifiedMessage.Close(); requestContext.Abort(); } } bool ShouldWrapException(Exception e) { return ((e is FormatException) || (e is XmlException)); } Message ProcessRequestContext(RequestContext requestContext, TimeSpan timeout, out SecurityProtocolCorrelationState correlationState, out bool isSecurityProcessingFailure) { correlationState = null; isSecurityProcessingFailure = false; if (requestContext == null) { return null; } Message result = null; Message message = requestContext.RequestMessage; bool cleanupContextState = true; try { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); Message unverifiedMessage = message; Exception securityException = null; try { correlationState = VerifyIncomingMessage(ref message, timeoutHelper.RemainingTime()); } catch (MessageSecurityException e) { isSecurityProcessingFailure = true; securityException = e; } if (securityException != null) { // SendFaultIfRequired closes the unverified message and context SendFaultIfRequired(securityException, unverifiedMessage, requestContext, timeoutHelper.RemainingTime()); cleanupContextState = false; return null; } else if (CheckIncomingToken(requestContext, message, correlationState, timeoutHelper.RemainingTime())) { if (message.Headers.Action == this.Settings.SecurityStandardsManager.SecureConversationDriver.CloseAction.Value) { SecurityTraceRecordHelper.TraceServerSessionCloseReceived(this.currentSessionToken, GetLocalUri()); this.isInputClosed = true; // OnCloseMessageReceived is responsible for closing the message and requestContext if required. this.OnCloseMessageReceived(requestContext, message, correlationState, timeoutHelper.RemainingTime()); correlationState = null; } else if (message.Headers.Action == this.Settings.SecurityStandardsManager.SecureConversationDriver.CloseResponseAction.Value) { SecurityTraceRecordHelper.TraceServerSessionCloseResponseReceived(this.currentSessionToken, GetLocalUri()); this.isInputClosed = true; // OnCloseResponseMessageReceived is responsible for closing the message and requestContext if required. this.OnCloseResponseMessageReceived(requestContext, message, correlationState, timeoutHelper.RemainingTime()); correlationState = null; } else { result = message; } cleanupContextState = false; } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if ((e is CommunicationException) || (e is TimeoutException) || (DiagnosticUtility.IsFatal(e)) || !ShouldWrapException(e)) { throw; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.MessageSecurityVerificationFailed), e)); } finally { if (cleanupContextState) { if (requestContext.RequestMessage != null) { requestContext.RequestMessage.Close(); } requestContext.Abort(); } } return result; } internal void CheckOutgoingToken() { lock (ThisLock) { if (this.currentSessionToken.KeyExpirationTime < DateTime.UtcNow) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SessionKeyExpiredException(SR.GetString(SR.SecuritySessionKeyIsStale))); } } } internal void SecureApplicationMessage(ref Message message, TimeSpan timeout, SecurityProtocolCorrelationState correlationState) { ThrowIfFaulted(); ThrowIfClosedOrNotOpen(); CheckOutgoingToken(); this.securityProtocol.SecureOutgoingMessage(ref message, timeout, correlationState); } internal SecurityProtocolCorrelationState VerifyIncomingMessage(ref Message message, TimeSpan timeout) { return this.securityProtocol.VerifyIncomingMessage(ref message, timeout, null); } void PrepareReply(Message request, Message reply) { if (request.Headers.ReplyTo != null) { request.Headers.ReplyTo.ApplyTo(reply); } else if (request.Headers.From != null) { request.Headers.From.ApplyTo(reply); } if (request.Headers.MessageId != null) { reply.Headers.RelatesTo = request.Headers.MessageId; } TraceUtility.CopyActivity(request, reply); if (TraceUtility.PropagateUserActivity || TraceUtility.ShouldPropagateActivity) { TraceUtility.AddActivityHeader(reply); } } protected void InitializeFaultCodesIfRequired() { if (!areFaultCodesInitialized) { lock (ThisLock) { if (!areFaultCodesInitialized) { SecurityStandardsManager standardsManager = this.securityProtocol.SecurityProtocolFactory.StandardsManager; SecureConversationDriver scDriver = standardsManager.SecureConversationDriver; renewFaultCode = FaultCode.CreateSenderFaultCode(scDriver.RenewNeededFaultCode.Value, scDriver.Namespace.Value); renewFaultReason = new FaultReason(SR.GetString(SR.SecurityRenewFaultReason), System.Globalization.CultureInfo.InvariantCulture); sessionAbortedFaultCode = FaultCode.CreateSenderFaultCode(DotNetSecurityStrings.SecuritySessionAbortedFault, DotNetSecurityStrings.Namespace); sessionAbortedFaultReason = new FaultReason(SR.GetString(SR.SecuritySessionAbortedFaultReason), System.Globalization.CultureInfo.InvariantCulture); areFaultCodesInitialized = true; } } } } void SendRenewFault(RequestContext requestContext, SecurityProtocolCorrelationState correlationState, TimeSpan timeout) { Message message = requestContext.RequestMessage; try { InitializeFaultCodesIfRequired(); MessageFault renewFault = MessageFault.CreateFault(renewFaultCode, renewFaultReason); Message response; if (message.Headers.MessageId != null) { response = Message.CreateMessage(message.Version, renewFault, DotNetSecurityStrings.SecuritySessionFaultAction); response.InitializeReply(message); } else { response = Message.CreateMessage(message.Version, renewFault, DotNetSecurityStrings.SecuritySessionFaultAction); } try { PrepareReply(message, response); TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); this.securityProtocol.SecureOutgoingMessage(ref response, timeoutHelper.RemainingTime(), correlationState); response.Properties.AllowOutputBatching = false; SendMessage(requestContext, response, timeoutHelper.RemainingTime()); } finally { response.Close(); } SecurityTraceRecordHelper.TraceSessionRenewalFaultSent(this.currentSessionToken, GetLocalUri(), message); } catch (CommunicationException e) { SecurityTraceRecordHelper.TraceRenewFaultSendFailure(this.currentSessionToken, GetLocalUri(), e); } catch (TimeoutException e) { SecurityTraceRecordHelper.TraceRenewFaultSendFailure(this.currentSessionToken, GetLocalUri(), e); } } Message ProcessCloseRequest(Message request) { RequestSecurityToken rst; XmlDictionaryReader bodyReader = request.GetReaderAtBodyContents(); using (bodyReader) { rst = this.Settings.SecurityStandardsManager.TrustDriver.CreateRequestSecurityToken(bodyReader); request.ReadFromBodyContentsToEnd(bodyReader); } if (rst.RequestType != null && rst.RequestType != this.Settings.SecurityStandardsManager.TrustDriver.RequestTypeClose) { throw TraceUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.InvalidRstRequestType, rst.RequestType)), request); } if (rst.CloseTarget == null) { throw TraceUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.NoCloseTargetSpecified)), request); } SecurityContextKeyIdentifierClause sctSkiClause = rst.CloseTarget as SecurityContextKeyIdentifierClause; if (sctSkiClause == null || !SecuritySessionSecurityTokenAuthenticator.DoesSkiClauseMatchSigningToken(sctSkiClause, request)) { throw TraceUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.BadCloseTarget, rst.CloseTarget)), request); } RequestSecurityTokenResponse rstr = new RequestSecurityTokenResponse(this.Settings.SecurityStandardsManager); rstr.Context = rst.Context; rstr.IsRequestedTokenClosed = true; rstr.MakeReadOnly(); BodyWriter bodyWriter = rstr; if (this.Settings.SecurityStandardsManager.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrust13) { List rstrList = new List (1); rstrList.Add(rstr); RequestSecurityTokenResponseCollection rstrc = new RequestSecurityTokenResponseCollection(rstrList, this.Settings.SecurityStandardsManager); bodyWriter = rstrc; } Message response = Message.CreateMessage(request.Version, ActionHeader.Create(this.Settings.SecurityStandardsManager.SecureConversationDriver.CloseResponseAction, request.Version.Addressing), bodyWriter); PrepareReply(request, response); return response; } internal Message CreateCloseResponse(Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout) { using (message) { Message response = this.ProcessCloseRequest(message); this.securityProtocol.SecureOutgoingMessage(ref response, timeout, correlationState); response.Properties.AllowOutputBatching = false; return response; } } internal void TraceSessionClosedResponseSuccess() { SecurityTraceRecordHelper.TraceSessionClosedResponseSent(this.currentSessionToken, GetLocalUri()); } internal void TraceSessionClosedResponseFailure(Exception e) { SecurityTraceRecordHelper.TraceSessionClosedResponseSendFailure(this.currentSessionToken, GetLocalUri(), e); } internal void TraceSessionClosedSuccess() { SecurityTraceRecordHelper.TraceSessionClosedSent(this.currentSessionToken, GetLocalUri()); } internal void TraceSessionClosedFailure(Exception e) { SecurityTraceRecordHelper.TraceSessionCloseSendFailure(this.currentSessionToken, GetLocalUri(), e); } // SendCloseResponse closes the message and underlying context if the operation completes successfully protected void SendCloseResponse(RequestContext requestContext, Message closeResponse, TimeSpan timeout) { try { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); using (closeResponse) { SendMessage(requestContext, closeResponse, timeoutHelper.RemainingTime()); } TraceSessionClosedResponseSuccess(); } catch (CommunicationException e) { TraceSessionClosedResponseFailure(e); } catch (TimeoutException e) { TraceSessionClosedResponseFailure(e); } } // BeginSendCloseResponse closes the message and underlying context if the operation completes successfully internal IAsyncResult BeginSendCloseResponse(RequestContext requestContext, Message closeResponse, TimeSpan timeout, AsyncCallback callback, object state) { try { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); return this.BeginSendMessage(requestContext, closeResponse, timeoutHelper.RemainingTime(), callback, state); } catch (CommunicationException e) { TraceSessionClosedResponseFailure(e); } catch (TimeoutException e) { TraceSessionClosedResponseFailure(e); } return new CompletedAsyncResult(callback, state); } // EndSendCloseResponse closes the message and underlying context if the operation completes successfully internal void EndSendCloseResponse(IAsyncResult result) { if (result is CompletedAsyncResult) { CompletedAsyncResult.End(result); return; } try { this.EndSendMessage(result); } catch (CommunicationException e) { TraceSessionClosedResponseFailure(e); } catch (TimeoutException e) { TraceSessionClosedResponseFailure(e); } } internal Message CreateCloseMessage(TimeSpan timeout) { RequestSecurityToken rst = new RequestSecurityToken(this.Settings.SecurityStandardsManager); rst.RequestType = this.Settings.SecurityStandardsManager.TrustDriver.RequestTypeClose; rst.CloseTarget = this.Settings.IssuedSecurityTokenParameters.CreateKeyIdentifierClause(this.currentSessionToken, SecurityTokenReferenceStyle.External); rst.MakeReadOnly(); Message closeMessage = Message.CreateMessage(this.messageVersion, ActionHeader.Create(this.Settings.SecurityStandardsManager.SecureConversationDriver.CloseAction, this.messageVersion.Addressing), rst); RequestReplyCorrelator.PrepareRequest(closeMessage); if (this.LocalAddress != null) { closeMessage.Headers.ReplyTo = this.LocalAddress; } else { if (closeMessage.Version.Addressing == AddressingVersion.WSAddressing10) { closeMessage.Headers.ReplyTo = null; } else if (closeMessage.Version.Addressing == AddressingVersion.WSAddressingAugust2004) { closeMessage.Headers.ReplyTo = EndpointAddress.AnonymousAddress; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ProtocolException(SR.GetString(SR.AddressingVersionNotSupported, closeMessage.Version.Addressing))); } } this.securityProtocol.SecureOutgoingMessage(ref closeMessage, timeout, null); closeMessage.Properties.AllowOutputBatching = false; return closeMessage; } protected void SendClose(TimeSpan timeout) { try { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); using (Message closeMessage = CreateCloseMessage(timeoutHelper.RemainingTime())) { SendMessage(null, closeMessage, timeoutHelper.RemainingTime()); } TraceSessionClosedSuccess(); } catch (CommunicationException e) { TraceSessionClosedFailure(e); } catch (TimeoutException e) { TraceSessionClosedFailure(e); } } internal IAsyncResult BeginSendClose(TimeSpan timeout, AsyncCallback callback, object state) { try { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); Message closeMessage = CreateCloseMessage(timeoutHelper.RemainingTime()); return this.BeginSendMessage(null, closeMessage, timeoutHelper.RemainingTime(), callback, state); } catch (CommunicationException e) { TraceSessionClosedFailure(e); } catch (TimeoutException e) { TraceSessionClosedFailure(e); } return new CompletedAsyncResult(callback, state); } internal void EndSendClose(IAsyncResult result) { if (result is CompletedAsyncResult) { CompletedAsyncResult.End(result); return; } try { this.EndSendMessage(result); } catch (CommunicationException e) { TraceSessionClosedFailure(e); } catch (TimeoutException e) { TraceSessionClosedFailure(e); } } protected void SendMessage(RequestContext requestContext, Message message, TimeSpan timeout) { if (this.channelBinder.CanSendAsynchronously) { this.channelBinder.Send(message, timeout); } else if (requestContext != null) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); requestContext.Reply(message, timeoutHelper.RemainingTime()); requestContext.Close(timeoutHelper.RemainingTime()); } } internal IAsyncResult BeginSendMessage(RequestContext requestContext, Message response, TimeSpan timeout, AsyncCallback callback, object state) { return new SendMessageAsyncResult(this, requestContext, response, timeout, callback, state); } internal void EndSendMessage(IAsyncResult result) { SendMessageAsyncResult.End(result); } class SendMessageAsyncResult : AsyncResult { static AsyncCallback sendCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(SendCallback)); ServerSecuritySessionChannel sessionChannel; TimeoutHelper timeoutHelper; RequestContext requestContext; Message message; public SendMessageAsyncResult(ServerSecuritySessionChannel sessionChannel, RequestContext requestContext, Message message, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.sessionChannel = sessionChannel; this.timeoutHelper = new TimeoutHelper(timeout); this.requestContext = requestContext; this.message = message; bool closeMessage = true; try { IAsyncResult result = this.BeginSend(message); if (!result.CompletedSynchronously) { closeMessage = false; return; } this.EndSend(result); closeMessage = false; } finally { if (closeMessage) { this.message.Close(); } } Complete(true); } IAsyncResult BeginSend(Message response) { if (this.sessionChannel.channelBinder.CanSendAsynchronously) { return this.sessionChannel.channelBinder.BeginSend(response, timeoutHelper.RemainingTime(), sendCallback, this); } else if (requestContext != null) { return requestContext.BeginReply(response, sendCallback, this); } else { return new SendCompletedAsyncResult(sendCallback, this); } } void EndSend(IAsyncResult result) { try { if (result is SendCompletedAsyncResult) { SendCompletedAsyncResult.End(result); } else if (this.sessionChannel.channelBinder.CanSendAsynchronously) { this.sessionChannel.channelBinder.EndSend(result); } else { this.requestContext.EndReply(result); this.requestContext.Close(timeoutHelper.RemainingTime()); } } finally { if (this.message != null) { this.message.Close(); } } } static void SendCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } SendMessageAsyncResult self = (SendMessageAsyncResult)(result.AsyncState); Exception completionException = null; try { self.EndSend(result); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) throw; completionException = e; } self.Complete(false, completionException); } public static void End(IAsyncResult result) { AsyncResult.End (result); } class SendCompletedAsyncResult : CompletedAsyncResult { public SendCompletedAsyncResult(AsyncCallback callback, object state) : base(callback, state) { } new public static void End(IAsyncResult result) { AsyncResult.End (result); } } } class CloseCoreAsyncResult : AsyncResult { static AsyncCallback channelBinderCloseCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(ChannelBinderCloseCallback)); static AsyncCallback settingsLifetimeManagerCloseCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(SettingsLifetimeManagerCloseCallback)); ServerSecuritySessionChannel channel; TimeoutHelper timeoutHelper; public CloseCoreAsyncResult(ServerSecuritySessionChannel channel, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.channel = channel; this.timeoutHelper = new TimeoutHelper(timeout); bool completeSelf = false; if (this.channel.channelBinder != null) { try { IAsyncResult result = this.channel.channelBinder.BeginClose(timeoutHelper.RemainingTime(), channelBinderCloseCallback, this); if (!result.CompletedSynchronously) { return; } this.channel.channelBinder.EndClose(result); } catch (CommunicationObjectAbortedException) { if (this.channel.State != CommunicationState.Closed) { throw; } else { completeSelf = true; } } } if (!completeSelf) { completeSelf = this.OnChannelBinderClosed(); } if (completeSelf) { RemoveSessionTokenFromCache(); Complete(true); } } void RemoveSessionTokenFromCache() { this.channel.Settings.SessionTokenCache.RemoveAllContexts(this.channel.currentSessionToken.ContextId); } static void ChannelBinderCloseCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseCoreAsyncResult self = (CloseCoreAsyncResult)(result.AsyncState); bool completeSelf = false; Exception completionException = null; try { try { self.channel.channelBinder.EndClose(result); } catch (CommunicationObjectAbortedException) { if (self.channel.State != CommunicationState.Closed) { throw; } completeSelf = true; } if (!completeSelf) { completeSelf = self.OnChannelBinderClosed(); } if (completeSelf) { self.RemoveSessionTokenFromCache(); } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) { throw; } completeSelf = true; completionException = e; } if (completeSelf) { self.Complete(false, completionException); } } bool OnChannelBinderClosed() { try { if (this.channel.securityProtocol != null) { this.channel.securityProtocol.Close(false, timeoutHelper.RemainingTime()); } bool closeLifetimeManager = false; lock (this.channel.ThisLock) { if (this.channel.hasSecurityStateReference) { closeLifetimeManager = true; this.channel.hasSecurityStateReference = false; } } if (!closeLifetimeManager) { return true; } IAsyncResult result = this.channel.settingsLifetimeManager.BeginClose(timeoutHelper.RemainingTime(), settingsLifetimeManagerCloseCallback, this); if (!result.CompletedSynchronously) { return false; } this.channel.settingsLifetimeManager.EndClose(result); return true; } catch (CommunicationObjectAbortedException) { if (channel.State != CommunicationState.Closed) { throw; } return true; } } static void SettingsLifetimeManagerCloseCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseCoreAsyncResult self = (CloseCoreAsyncResult)(result.AsyncState); bool removeSessionToken = false; Exception completionException = null; try { self.channel.settingsLifetimeManager.EndClose(result); removeSessionToken = true; } catch (CommunicationObjectAbortedException) { if (self.channel.State != CommunicationState.Closed) { throw; } removeSessionToken = true; } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) { throw; } completionException = e; } finally { if (removeSessionToken) { self.RemoveSessionTokenFromCache(); } } self.Complete(false, completionException); } public static void End(IAsyncResult result) { AsyncResult.End (result); } } protected class SoapSecurityInputSession : ISecureConversationSession, IInputSession { ServerSecuritySessionChannel channel; UniqueId securityContextTokenId; EndpointIdentity remoteIdentity; SecurityKeyIdentifierClause sessionTokenIdentifier; SecurityStandardsManager standardsManager; public SoapSecurityInputSession(SecurityContextSecurityToken sessionToken, SecuritySessionServerSettings settings, ServerSecuritySessionChannel channel) { this.channel = channel; this.securityContextTokenId = sessionToken.ContextId; Claim identityClaim = SecurityUtils.GetPrimaryIdentityClaim(sessionToken.AuthorizationPolicies); if (identityClaim != null) { this.remoteIdentity = EndpointIdentity.CreateIdentity(identityClaim); } this.sessionTokenIdentifier = settings.IssuedSecurityTokenParameters.CreateKeyIdentifierClause(sessionToken, SecurityTokenReferenceStyle.External); this.standardsManager = settings.SessionProtocolFactory.StandardsManager; } public string Id { get { return this.securityContextTokenId.ToString(); } } public EndpointIdentity RemoteIdentity { get { return this.remoteIdentity; } } public void WriteSessionTokenIdentifier(XmlDictionaryWriter writer) { this.channel.ThrowIfDisposedOrNotOpen(); this.standardsManager.SecurityTokenSerializer.WriteKeyIdentifierClause(writer, this.sessionTokenIdentifier); } public bool TryReadSessionTokenIdentifier(XmlReader reader) { this.channel.ThrowIfDisposedOrNotOpen(); if (!this.standardsManager.SecurityTokenSerializer.CanReadKeyIdentifierClause(reader)) { return false; } SecurityContextKeyIdentifierClause incomingTokenIdentifier = this.standardsManager.SecurityTokenSerializer.ReadKeyIdentifierClause(reader) as SecurityContextKeyIdentifierClause; return incomingTokenIdentifier != null && incomingTokenIdentifier.Matches(this.securityContextTokenId, null); } } class ReceiveRequestAsyncResult : AsyncResult { static WaitCallback onWait = new WaitCallback(OnWait); static AsyncCallback onReceive = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnReceive)); ServerSecuritySessionChannel channel; RequestContext innerRequestContext; Message requestMessage; SecurityProtocolCorrelationState correlationState; bool expired; TimeoutHelper timeoutHelper; public ReceiveRequestAsyncResult(ServerSecuritySessionChannel channel, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { channel.ThrowIfFaulted(); this.timeoutHelper = new TimeoutHelper(timeout); this.channel = channel; if (!channel.receiveLock.Enter(onWait, this)) { return; } bool completeSelf = false; bool throwing = true; try { completeSelf = WaitComplete(); throwing = false; } finally { if (throwing) { this.channel.receiveLock.Exit(); } } if (completeSelf) { Complete(true); } } static void OnWait(object state) { ReceiveRequestAsyncResult self = (ReceiveRequestAsyncResult)state; bool completeSelf = false; Exception completionException = null; try { completeSelf = self.WaitComplete(); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) throw; completeSelf = true; completionException = e; } if (completeSelf) { self.Complete(false, completionException); } } bool WaitComplete() { if (channel.isInputClosed) { return true; } channel.ThrowIfFaulted(); ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity && channel.initialRequestContext != null ? TraceUtility.ExtractActivity(channel.initialRequestContext.RequestMessage) : null; using (ServiceModelActivity.BoundOperation(activity)) { if (channel.initialRequestContext != null) { innerRequestContext = channel.initialRequestContext; channel.initialRequestContext = null; bool isSecurityProcessingFailure; requestMessage = channel.ProcessRequestContext(innerRequestContext, timeoutHelper.RemainingTime(), out this.correlationState, out isSecurityProcessingFailure); if (requestMessage != null || channel.isInputClosed) { this.expired = false; return true; } } if (this.timeoutHelper.RemainingTimeExpireNegative() < TimeSpan.Zero) { this.expired = true; return true; } IAsyncResult result = channel.ChannelBinder.BeginTryReceive(this.timeoutHelper.RemainingTime(), onReceive, this); if (!result.CompletedSynchronously) return false; return CompleteReceive(result); } } bool CompleteReceive(IAsyncResult result) { while (true) { this.expired = !channel.ChannelBinder.EndTryReceive(result, out this.innerRequestContext); if (this.expired || innerRequestContext == null) break; bool isSecurityProcessingFailure; requestMessage = channel.ProcessRequestContext(innerRequestContext, timeoutHelper.RemainingTime(), out this.correlationState, out isSecurityProcessingFailure); if (requestMessage != null) { if (channel.isInputClosed) { ProtocolException error = ProtocolException.ReceiveShutdownReturnedNonNull(requestMessage); try { throw TraceUtility.ThrowHelperWarning(error, requestMessage); } finally { requestMessage.Close(); innerRequestContext.Abort(); } } break; } if (channel.isInputClosed || channel.State == CommunicationState.Faulted) break; // retry the receive unless the timeout is reached if (this.timeoutHelper.RemainingTimeExpireNegative() < TimeSpan.Zero) { this.expired = true; break; } result = channel.ChannelBinder.BeginTryReceive(this.timeoutHelper.RemainingTime(), onReceive, this); if (!result.CompletedSynchronously) return false; } this.channel.ThrowIfFaulted(); return true; } new void Complete(bool synchronous) { this.channel.receiveLock.Exit(); base.Complete(synchronous); } new void Complete(bool synchronous, Exception exception) { this.channel.receiveLock.Exit(); base.Complete(synchronous, exception); } static ReceiveRequestAsyncResult End(IAsyncResult result) { return AsyncResult.End (result); } public static bool EndAsMessage(IAsyncResult result, out Message message) { ReceiveRequestAsyncResult receiveResult = End(result); message = receiveResult.requestMessage; // if the message is not null, then dispose the inner request context // if the message is null its either a close or protocol fault in which case the request context // will be closed by the channel if (message != null) { if (receiveResult.innerRequestContext != null) { try { receiveResult.innerRequestContext.Close(receiveResult.timeoutHelper.RemainingTime()); } catch (TimeoutException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, System.Diagnostics.TraceEventType.Information); } } } return !receiveResult.expired; } public static bool EndAsRequestContext(IAsyncResult result, out RequestContext requestContext) { ReceiveRequestAsyncResult receiveResult = End(result); if (receiveResult.requestMessage == null) { requestContext = null; } else { requestContext = new SecuritySessionRequestContext(receiveResult.innerRequestContext, receiveResult.requestMessage, receiveResult.correlationState, receiveResult.channel); } return !receiveResult.expired; } static void OnReceive(IAsyncResult result) { if (result.CompletedSynchronously) return; ReceiveRequestAsyncResult self = (ReceiveRequestAsyncResult)result.AsyncState; bool completeSelf = false; Exception completionException = null; try { completeSelf = self.CompleteReceive(result); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) throw; completeSelf = true; completionException = e; } if (completeSelf) { self.Complete(false, completionException); } } } } abstract class ServerSecuritySimplexSessionChannel : ServerSecuritySessionChannel { SoapSecurityInputSession session; bool receivedClose; bool canSendCloseResponse; bool sentCloseResponse; RequestContext closeRequestContext; Message closeResponse; InterruptibleWaitObject inputSessionClosedHandle = new InterruptibleWaitObject(false); public ServerSecuritySimplexSessionChannel( SecuritySessionServerSettings settings, IServerReliableChannelBinder channelBinder, SecurityContextSecurityToken sessionToken, object listenerSecurityState, SecurityListenerSettingsLifetimeManager settingsLifetimeManager) : base(settings, channelBinder, sessionToken, listenerSecurityState, settingsLifetimeManager) { this.session = new SoapSecurityInputSession(sessionToken, settings, this); } public IInputSession Session { get { return this.session; } } void CleanupPendingCloseState() { lock (ThisLock) { if (this.closeResponse != null) { this.closeResponse.Close(); this.closeResponse = null; } if (this.closeRequestContext != null) { this.closeRequestContext.Abort(); this.closeRequestContext = null; } } } protected override void AbortCore() { base.AbortCore(); this.Settings.RemoveSessionChannel(this.session.Id); CleanupPendingCloseState(); } protected override void CloseCore(TimeSpan timeout) { base.CloseCore(timeout); this.inputSessionClosedHandle.Abort(this); this.Settings.RemoveSessionChannel(this.session.Id); } protected override void EndCloseCore(IAsyncResult result) { base.EndCloseCore(result); this.inputSessionClosedHandle.Abort(this); this.Settings.RemoveSessionChannel(this.session.Id); } protected override void OnAbort() { AbortCore(); this.inputSessionClosedHandle.Abort(this); } protected override void OnFaulted() { this.AbortCore(); this.inputSessionClosedHandle.Fault(this); base.OnFaulted(); } bool ShouldSendCloseResponseOnClose(out RequestContext pendingCloseRequestContext, out Message pendingCloseResponse) { bool sendCloseResponse = false; lock (ThisLock) { this.canSendCloseResponse = true; if (!this.sentCloseResponse && this.receivedClose && this.closeResponse != null) { this.sentCloseResponse = true; sendCloseResponse = true; pendingCloseRequestContext = this.closeRequestContext; pendingCloseResponse = this.closeResponse; this.closeResponse = null; this.closeRequestContext = null; } else { canSendCloseResponse = false; pendingCloseRequestContext = null; pendingCloseResponse = null; } } return sendCloseResponse; } bool SendCloseResponseOnCloseIfRequired(TimeSpan timeout) { bool aborted = false; RequestContext pendingCloseRequestContext; Message pendingCloseResponse; bool sendCloseResponse = ShouldSendCloseResponseOnClose(out pendingCloseRequestContext, out pendingCloseResponse); TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); bool cleanupCloseState = true; if (sendCloseResponse) { try { this.SendCloseResponse(pendingCloseRequestContext, pendingCloseResponse, timeoutHelper.RemainingTime()); this.inputSessionClosedHandle.Set(); cleanupCloseState = false; } catch (CommunicationObjectAbortedException) { if (this.State != CommunicationState.Closed) { throw; } aborted = true; } finally { if (cleanupCloseState) { if (pendingCloseResponse != null) { pendingCloseResponse.Close(); } if (pendingCloseRequestContext != null) { pendingCloseRequestContext.Abort(); } } } } return aborted; } protected override void OnClose(TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); // send a close response if one was not sent yet bool wasAborted = SendCloseResponseOnCloseIfRequired(timeoutHelper.RemainingTime()); if (wasAborted) { return; } bool wasInputSessionClosed = this.WaitForInputSessionClose(timeoutHelper.RemainingTime(), out wasAborted); if (wasAborted) { return; } if (!wasInputSessionClosed) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, timeoutHelper.OriginalTimeout))); } else { this.CloseCore(timeoutHelper.RemainingTime()); } } protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) { RequestContext pendingCloseRequestContext; Message pendingCloseResponse; bool sendCloseResponse = ShouldSendCloseResponseOnClose(out pendingCloseRequestContext, out pendingCloseResponse); return new CloseAsyncResult(this, sendCloseResponse, pendingCloseRequestContext, pendingCloseResponse, timeout, callback, state); } protected override void OnEndClose(IAsyncResult result) { CloseAsyncResult.End(result); } bool WaitForInputSessionClose(TimeSpan timeout, out bool wasAborted) { Message message; TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); wasAborted = false; try { if (this.TryReceive(timeoutHelper.RemainingTime(), out message)) { if (message != null) { using (message) { ProtocolException error = ProtocolException.ReceiveShutdownReturnedNonNull(message); throw TraceUtility.ThrowHelperWarning(error, message); } } return this.inputSessionClosedHandle.Wait(timeoutHelper.RemainingTime(), false); } } catch (CommunicationObjectAbortedException) { if (this.State != CommunicationState.Closed) { throw; } wasAborted = true; } return false; } protected override void OnCloseResponseMessageReceived(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout) { // we dont expect a close-response for non-duplex security session message.Close(); requestContext.Abort(); this.Fault(new ProtocolException(SR.GetString(SR.UnexpectedSecuritySessionCloseResponse))); } protected override void OnCloseMessageReceived(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout) { if (this.State == CommunicationState.Created) { DiagnosticUtility.DebugAssert("ServerSecuritySimplexSessionChannel.OnCloseMessageReceived (this.State == Created)"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ServerReceivedCloseMessageStateIsCreated, this.GetType().ToString()))); } if (SendCloseResponseOnCloseReceivedIfRequired(requestContext, message, correlationState, timeout)) { this.inputSessionClosedHandle.Set(); } } bool SendCloseResponseOnCloseReceivedIfRequired(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout) { bool sendCloseResponse = false; ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? TraceUtility.ExtractActivity(message) : null; bool cleanupContext = true; try { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); Message localCloseResponse = null; lock (ThisLock) { if (!this.receivedClose) { this.receivedClose = true; localCloseResponse = CreateCloseResponse(message, correlationState, timeoutHelper.RemainingTime()); if (canSendCloseResponse) { this.sentCloseResponse = true; sendCloseResponse = true; } else { // save the close requestContext to reply later this.closeRequestContext = requestContext; this.closeResponse = localCloseResponse; cleanupContext = false; } } } if (sendCloseResponse) { this.SendCloseResponse(requestContext, localCloseResponse, timeoutHelper.RemainingTime()); cleanupContext = false; } else if (cleanupContext) { requestContext.Close(timeoutHelper.RemainingTime()); cleanupContext = false; } return sendCloseResponse; } finally { message.Close(); if (cleanupContext) { requestContext.Abort(); } if (DiagnosticUtility.ShouldUseActivity) { activity.Stop(); } } } class CloseAsyncResult : AsyncResult { static readonly AsyncCallback sendCloseResponseCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(SendCloseResponseCallback)); static readonly AsyncCallback receiveCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(ReceiveCallback)); static readonly AsyncCallback waitCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(WaitForInputSessionCloseCallback)); static readonly AsyncCallback closeCoreCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(CloseCoreCallback)); ServerSecuritySimplexSessionChannel sessionChannel; TimeoutHelper timeoutHelper; RequestContext closeRequestContext; Message closeResponse; public CloseAsyncResult(ServerSecuritySimplexSessionChannel sessionChannel, bool sendCloseResponse, RequestContext closeRequestContext, Message closeResponse, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.timeoutHelper = new TimeoutHelper(timeout); this.sessionChannel = sessionChannel; this.closeRequestContext = closeRequestContext; this.closeResponse = closeResponse; bool wasChannelAborted = false; bool completeSelf = this.OnSendCloseResponse(sendCloseResponse, out wasChannelAborted); if (wasChannelAborted || completeSelf) { Complete(true); } } bool OnSendCloseResponse(bool shouldSendCloseResponse, out bool wasChannelAborted) { wasChannelAborted = false; try { if (shouldSendCloseResponse) { bool cleanupCloseState = true; try { IAsyncResult result = this.sessionChannel.BeginSendCloseResponse(closeRequestContext, closeResponse, timeoutHelper.RemainingTime(), sendCloseResponseCallback, this); if (!result.CompletedSynchronously) { cleanupCloseState = false; return false; } this.sessionChannel.EndSendCloseResponse(result); this.sessionChannel.inputSessionClosedHandle.Set(); } finally { if (cleanupCloseState) { CleanupCloseState(); } } } } catch (CommunicationObjectAbortedException) { if (this.sessionChannel.State != CommunicationState.Closed) { throw; } wasChannelAborted = true; } if (wasChannelAborted) { return true; } return this.OnReceiveNullMessage(out wasChannelAborted); } void CleanupCloseState() { if (this.closeResponse != null) { this.closeResponse.Close(); } if (this.closeRequestContext != null) { this.closeRequestContext.Abort(); } } static void SendCloseResponseCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState; bool completeSelf = false; Exception completionException = null; try { bool wasAborted = false; try { thisResult.sessionChannel.EndSendCloseResponse(result); thisResult.sessionChannel.inputSessionClosedHandle.Set(); } catch (CommunicationObjectAbortedException) { if (thisResult.sessionChannel.State != CommunicationState.Closed) { throw; } wasAborted = true; completeSelf = true; } finally { thisResult.CleanupCloseState(); } if (!wasAborted) { completeSelf = thisResult.OnReceiveNullMessage(out wasAborted); } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) throw; completeSelf = true; completionException = e; } if (completeSelf) { thisResult.Complete(false, completionException); } } bool OnReceiveNullMessage(out bool wasChannelAborted) { wasChannelAborted = false; bool receivedMessage = false; Message message = null; try { IAsyncResult result = this.sessionChannel.BeginTryReceive(this.timeoutHelper.RemainingTime(), receiveCallback, this); if (!result.CompletedSynchronously) { return false; } receivedMessage = this.sessionChannel.EndTryReceive(result, out message); } catch (CommunicationObjectAbortedException) { if (this.sessionChannel.State != CommunicationState.Closed) { throw; } // another thread aborted the channel wasChannelAborted = true; } if (wasChannelAborted) { return true; } if (receivedMessage) { return this.OnMessageReceived(message); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, timeoutHelper.OriginalTimeout))); } } static void ReceiveCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState; bool completeSelf = false; Exception completionException = null; try { Message message = null; bool wasAborted = false; bool receivedMessage = false; try { receivedMessage = thisResult.sessionChannel.EndTryReceive(result, out message); } catch (CommunicationObjectAbortedException) { if (thisResult.sessionChannel.State != CommunicationState.Closed) { throw; } wasAborted = true; completeSelf = true; } if (!wasAborted) { if (receivedMessage) { completeSelf = thisResult.OnMessageReceived(message); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, thisResult.timeoutHelper.OriginalTimeout))); } } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) throw; completeSelf = true; completionException = e; } if (completeSelf) { thisResult.Complete(false, completionException); } } bool OnMessageReceived(Message message) { if (message != null) { using (message) { ProtocolException error = ProtocolException.ReceiveShutdownReturnedNonNull(message); throw TraceUtility.ThrowHelperWarning(error, message); } } bool inputSessionClosed = false; try { IAsyncResult result = this.sessionChannel.inputSessionClosedHandle.BeginWait(this.timeoutHelper.RemainingTime(), true, waitCallback, this); if (!result.CompletedSynchronously) { return false; } this.sessionChannel.inputSessionClosedHandle.EndWait(result); inputSessionClosed = true; } catch (CommunicationObjectAbortedException) { if (this.sessionChannel.State != CommunicationState.Closed) { throw; } // a parallel thread aborted the channel return true; } catch (TimeoutException) { inputSessionClosed = false; } return this.OnWaitOver(inputSessionClosed); } static void WaitForInputSessionCloseCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState; bool completeSelf = false; Exception completionException = null; try { bool inputSessionClosed = false; bool wasChannelAborted = false; try { thisResult.sessionChannel.inputSessionClosedHandle.EndWait(result); inputSessionClosed = true; } catch (TimeoutException) { inputSessionClosed = false; } catch (CommunicationObjectAbortedException) { if (thisResult.sessionChannel.State != CommunicationState.Closed) { throw; } wasChannelAborted = true; completeSelf = true; } if (!wasChannelAborted) { completeSelf = thisResult.OnWaitOver(inputSessionClosed); } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) throw; completeSelf = true; completionException = e; } if (completeSelf) { thisResult.Complete(false, completionException); } } bool OnWaitOver(bool closeCompleted) { if (closeCompleted) { IAsyncResult result = this.sessionChannel.BeginCloseCore(this.timeoutHelper.RemainingTime(), closeCoreCallback, this); if (!result.CompletedSynchronously) { return false; } this.sessionChannel.EndCloseCore(result); return true; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, this.timeoutHelper.OriginalTimeout))); } } static void CloseCoreCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseAsyncResult self = (CloseAsyncResult)(result.AsyncState); Exception completionException = null; try { self.sessionChannel.EndCloseCore(result); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) { throw; } completionException = e; } self.Complete(false, completionException); } public static void End(IAsyncResult result) { AsyncResult.End (result); } } } class SecurityReplySessionChannel : ServerSecuritySimplexSessionChannel, IReplySessionChannel { public SecurityReplySessionChannel( SecuritySessionServerSettings settings, IServerReliableChannelBinder channelBinder, SecurityContextSecurityToken sessionToken, object listenerSecurityState, SecurityListenerSettingsLifetimeManager settingsLifetimeManager) : base(settings, channelBinder, sessionToken, listenerSecurityState, settingsLifetimeManager) { } protected override bool CanDoSecurityCorrelation { get { return true; } } public bool WaitForRequest(TimeSpan timeout) { return this.ChannelBinder.WaitForRequest(timeout); } public IAsyncResult BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback, object state) { return this.ChannelBinder.BeginWaitForRequest(timeout, callback, state); } public bool EndWaitForRequest(IAsyncResult result) { return this.ChannelBinder.EndWaitForRequest(result); } } class SecuritySessionRequestContext : RequestContextBase { RequestContext requestContext; ServerSecuritySessionChannel channel; SecurityProtocolCorrelationState correlationState; public SecuritySessionRequestContext(RequestContext requestContext, Message requestMessage, SecurityProtocolCorrelationState correlationState, ServerSecuritySessionChannel channel) : base(requestMessage, channel.InternalCloseTimeout, channel.InternalSendTimeout) { this.requestContext = requestContext; this.correlationState = correlationState; this.channel = channel; } protected override void OnAbort() { this.requestContext.Abort(); } protected override void OnClose(TimeSpan timeout) { this.requestContext.Close(timeout); } protected override void OnReply(Message message, TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); if (message != null) { this.channel.SecureApplicationMessage(ref message, timeoutHelper.RemainingTime(), correlationState); } this.requestContext.Reply(message, timeoutHelper.RemainingTime()); } protected override IAsyncResult OnBeginReply(Message message, TimeSpan timeout, AsyncCallback callback, object state) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); if (message != null) { this.channel.SecureApplicationMessage(ref message, timeoutHelper.RemainingTime(), correlationState); } return this.requestContext.BeginReply(message, timeoutHelper.RemainingTime(), callback, state); } protected override void OnEndReply(IAsyncResult result) { this.requestContext.EndReply(result); } } class ServerSecurityDuplexSessionChannel : ServerSecuritySessionChannel, IDuplexSessionChannel { SoapSecurityServerDuplexSession session; bool isInputClosed; bool isOutputClosed; bool sentClose; bool receivedClose; RequestContext closeRequestContext; Message closeResponseMessage; InterruptibleWaitObject outputSessionCloseHandle = new InterruptibleWaitObject(true); InterruptibleWaitObject inputSessionCloseHandle = new InterruptibleWaitObject(false); public ServerSecurityDuplexSessionChannel( SecuritySessionServerSettings settings, IServerReliableChannelBinder channelBinder, SecurityContextSecurityToken sessionToken, object listenerSecurityState, SecurityListenerSettingsLifetimeManager settingsLifetimeManager) : base(settings, channelBinder, sessionToken, listenerSecurityState, settingsLifetimeManager) { this.session = new SoapSecurityServerDuplexSession(sessionToken, settings, this); } public EndpointAddress RemoteAddress { get { return this.ChannelBinder.RemoteAddress; } } public Uri Via { get { return this.RemoteAddress.Uri; } } public IDuplexSession Session { get { return this.session; } } public void Send(Message message) { this.Send(message, this.DefaultSendTimeout); } public void Send(Message message, TimeSpan timeout) { CheckOutputOpen(); TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); this.SecureApplicationMessage(ref message, timeoutHelper.RemainingTime(), null); this.ChannelBinder.Send(message, timeoutHelper.RemainingTime()); } public IAsyncResult BeginSend(Message message, AsyncCallback callback, object state) { return this.BeginSend(message, this.DefaultSendTimeout, callback, state); } public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state) { CheckOutputOpen(); TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); this.SecureApplicationMessage(ref message, timeoutHelper.RemainingTime(), null); return this.ChannelBinder.BeginSend(message, timeoutHelper.RemainingTime(), callback, state); } public void EndSend(IAsyncResult result) { this.ChannelBinder.EndSend(result); } protected override void AbortCore() { base.AbortCore(); this.Settings.RemoveSessionChannel(this.session.Id); CleanupPendingCloseState(); } void CleanupPendingCloseState() { lock (ThisLock) { if (this.closeResponseMessage != null) { this.closeResponseMessage.Close(); this.closeResponseMessage = null; } if (this.closeRequestContext != null) { this.closeRequestContext.Abort(); this.closeRequestContext = null; } } } protected override void OnAbort() { AbortCore(); this.inputSessionCloseHandle.Abort(this); this.outputSessionCloseHandle.Abort(this); } protected override void OnFaulted() { this.AbortCore(); this.inputSessionCloseHandle.Fault(this); this.outputSessionCloseHandle.Fault(this); base.OnFaulted(); } protected override void CloseCore(TimeSpan timeout) { base.CloseCore(timeout); this.inputSessionCloseHandle.Abort(this); this.outputSessionCloseHandle.Abort(this); this.Settings.RemoveSessionChannel(this.session.Id); } protected override void EndCloseCore(IAsyncResult result) { base.EndCloseCore(result); this.inputSessionCloseHandle.Abort(this); this.outputSessionCloseHandle.Abort(this); this.Settings.RemoveSessionChannel(this.session.Id); } protected void CheckOutputOpen() { ThrowIfClosedOrNotOpen(); lock (ThisLock) { if (this.isOutputClosed) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new CommunicationException(SR.GetString(SR.OutputNotExpected))); } } } protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) { return new CloseAsyncResult(this, timeout, callback, state); } protected override void OnEndClose(IAsyncResult result) { CloseAsyncResult.End(result); } internal bool WaitForOutputSessionClose(TimeSpan timeout, out bool wasAborted) { wasAborted = false; try { return this.outputSessionCloseHandle.Wait(timeout, false); } catch (CommunicationObjectAbortedException) { if (this.State != CommunicationState.Closed) throw; wasAborted = true; return true; } } protected override void OnClose(TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); // step 1: close output session this.CloseOutputSession(timeoutHelper.RemainingTime()); // if the channel was aborted while closing the output session, return if (this.State == CommunicationState.Closed) { return; } // step 2: wait for input session to be closed bool wasAborted; bool didInputSessionClose = this.WaitForInputSessionClose(timeoutHelper.RemainingTime(), out wasAborted); if (wasAborted) { return; } if (!didInputSessionClose) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, timeoutHelper.OriginalTimeout))); } // wait for any concurrent CloseOutputSessions to finish bool didOutputSessionClose = this.WaitForOutputSessionClose(timeoutHelper.RemainingTime(), out wasAborted); if (wasAborted) { return; } if (!didOutputSessionClose) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseOutputSessionTimeout, timeoutHelper.OriginalTimeout))); } this.CloseCore(timeoutHelper.RemainingTime()); } bool WaitForInputSessionClose(TimeSpan timeout, out bool wasAborted) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); Message message; wasAborted = false; try { if (!this.TryReceive(timeoutHelper.RemainingTime(), out message)) { return false; } if (message != null) { using (message) { ProtocolException error = ProtocolException.ReceiveShutdownReturnedNonNull(message); throw TraceUtility.ThrowHelperWarning(error, message); } } // wait for remote close if (!this.inputSessionCloseHandle.Wait(timeoutHelper.RemainingTime(), false)) { return false; } else { lock (ThisLock) { if (!(this.isInputClosed)) { DiagnosticUtility.DebugAssert("Shutdown request was not received."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ShutdownRequestWasNotReceived))); } } return true; } } catch (CommunicationObjectAbortedException) { if (this.State != CommunicationState.Closed) { throw; } wasAborted = true; } return false; } protected override void OnCloseMessageReceived(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout) { if (this.State == CommunicationState.Created) { DiagnosticUtility.DebugAssert("ServerSecurityDuplexSessionChannel.OnCloseMessageReceived (this.State == Created)"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ServerReceivedCloseMessageStateIsCreated, this.GetType().ToString()))); } TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); bool setInputSessionCloseHandle = false; bool cleanupContext = true; try { lock (ThisLock) { this.receivedClose = true; if (!this.isInputClosed) { this.isInputClosed = true; setInputSessionCloseHandle = true; if (!this.isOutputClosed) { this.closeRequestContext = requestContext; // CreateCloseResponse closes the message passed in this.closeResponseMessage = CreateCloseResponse(message, null, timeoutHelper.RemainingTime()); cleanupContext = false; } } } if (setInputSessionCloseHandle) { this.inputSessionCloseHandle.Set(); } if (cleanupContext) { requestContext.Close(timeoutHelper.RemainingTime()); cleanupContext = false; } } finally { message.Close(); if (cleanupContext) { requestContext.Abort(); } } } protected override void OnCloseResponseMessageReceived(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout) { bool cleanupContext = true; try { bool isCloseResponseExpected = false; bool setInputSessionCloseHandle = false; lock (ThisLock) { isCloseResponseExpected = this.sentClose; if (isCloseResponseExpected && !this.isInputClosed) { this.isInputClosed = true; setInputSessionCloseHandle = true; } } if (!isCloseResponseExpected) { this.Fault(new ProtocolException(SR.GetString(SR.UnexpectedSecuritySessionCloseResponse))); return; } if (setInputSessionCloseHandle) { this.inputSessionCloseHandle.Set(); } requestContext.Close(timeout); cleanupContext = false; } finally { message.Close(); if (cleanupContext) { requestContext.Abort(); } } } void DetermineCloseOutputSessionMessage(out bool sendClose, out bool sendCloseResponse, out Message pendingCloseResponseMessage, out RequestContext pendingCloseRequestContext) { sendClose = false; sendCloseResponse = false; pendingCloseResponseMessage = null; pendingCloseRequestContext = null; lock (ThisLock) { if (!this.isOutputClosed) { this.isOutputClosed = true; if (this.receivedClose) { if (this.closeResponseMessage != null) { pendingCloseResponseMessage = this.closeResponseMessage; pendingCloseRequestContext = this.closeRequestContext; this.closeResponseMessage = null; this.closeRequestContext = null; sendCloseResponse = true; } } else { sendClose = true; this.sentClose = true; } this.outputSessionCloseHandle.Reset(); } } } void CloseOutputSession(TimeSpan timeout) { bool sendClose = false; bool sendCloseResponse = false; Message pendingCloseResponseMessage; RequestContext pendingCloseRequestContext; try { DetermineCloseOutputSessionMessage(out sendClose, out sendCloseResponse, out pendingCloseResponseMessage, out pendingCloseRequestContext); if (sendCloseResponse) { bool cleanupCloseState = true; try { this.SendCloseResponse(pendingCloseRequestContext, pendingCloseResponseMessage, timeout); cleanupCloseState = false; } finally { if (cleanupCloseState) { pendingCloseResponseMessage.Close(); pendingCloseRequestContext.Abort(); } } } else if (sendClose) { this.SendClose(timeout); } } catch (CommunicationObjectAbortedException) { if (this.State != CommunicationState.Closed) throw; // a parallel thread aborted the channel. ignore the exception } finally { if (sendClose || sendCloseResponse) { this.outputSessionCloseHandle.Set(); } } } IAsyncResult BeginCloseOutputSession(TimeSpan timeout, AsyncCallback callback, object state) { return new CloseOutputSessionAsyncResult(this, timeout, callback, state); } void EndCloseOutputSession(IAsyncResult result) { CloseOutputSessionAsyncResult.End(result); } public bool WaitForMessage(TimeSpan timeout) { return this.ChannelBinder.WaitForRequest(timeout); } public IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state) { return this.ChannelBinder.BeginWaitForRequest(timeout, callback, state); } public bool EndWaitForMessage(IAsyncResult result) { return this.ChannelBinder.EndWaitForRequest(result); } class CloseOutputSessionAsyncResult : AsyncResult { static AsyncCallback sendCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(SendCallback)); ServerSecurityDuplexSessionChannel sessionChannel; TimeoutHelper timeoutHelper; bool sendClose; bool sendCloseResponse; Message closeResponseMessage; RequestContext closeRequestContext; public CloseOutputSessionAsyncResult(ServerSecurityDuplexSessionChannel sessionChannel, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.sessionChannel = sessionChannel; this.timeoutHelper = new TimeoutHelper(timeout); this.sessionChannel.DetermineCloseOutputSessionMessage(out sendClose, out sendCloseResponse, out closeResponseMessage, out closeRequestContext); if (!sendClose && !sendCloseResponse) { Complete(true); return; } bool doCleanup = true; try { IAsyncResult result = this.BeginSend(sendCallback, this); if (!result.CompletedSynchronously) { doCleanup = false; return; } this.EndSend(result); } finally { if (doCleanup) { Cleanup(); } } Complete(true); } static void SendCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseOutputSessionAsyncResult self = (CloseOutputSessionAsyncResult)(result.AsyncState); Exception completionException = null; try { self.EndSend(result); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) throw; completionException = e; } self.Cleanup(); self.Complete(false, completionException); } IAsyncResult BeginSend(AsyncCallback callback, object state) { if (this.sendClose) { return this.sessionChannel.BeginSendClose(timeoutHelper.RemainingTime(), callback, state); } else { return this.sessionChannel.BeginSendCloseResponse(this.closeRequestContext, this.closeResponseMessage, this. timeoutHelper.RemainingTime(), callback, state); } } void EndSend(IAsyncResult result) { if (this.sendClose) { this.sessionChannel.EndSendClose(result); } else { this.sessionChannel.EndSendCloseResponse(result); } } void Cleanup() { if (this.closeResponseMessage != null) { this.closeResponseMessage.Close(); } if (this.closeRequestContext != null) { this.closeRequestContext.Abort(); } this.sessionChannel.outputSessionCloseHandle.Set(); } public static void End(IAsyncResult result) { AsyncResult.End (result); } } class CloseAsyncResult : AsyncResult { static readonly AsyncCallback receiveCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(ReceiveCallback)); static readonly AsyncCallback inputSessionWaitCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(WaitForInputSessionCloseCallback)); static readonly AsyncCallback closeOutputSessionCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(CloseOutputSessionCallback)); static readonly AsyncCallback outputSessionWaitCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(WaitForOutputSessionCloseCallback)); static readonly AsyncCallback closeCoreCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(CloseCoreCallback)); ServerSecurityDuplexSessionChannel sessionChannel; TimeoutHelper timeoutHelper; public CloseAsyncResult(ServerSecurityDuplexSessionChannel sessionChannel, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.timeoutHelper = new TimeoutHelper(timeout); this.sessionChannel = sessionChannel; bool wasAborted = false; try { IAsyncResult result = this.sessionChannel.BeginCloseOutputSession(timeoutHelper.RemainingTime(), closeOutputSessionCallback, this); if (!result.CompletedSynchronously) { return; } this.sessionChannel.EndCloseOutputSession(result); } catch (CommunicationObjectAbortedException) { if (sessionChannel.State != CommunicationState.Closed) throw; // a parallel thread must have aborted the channel. No need to close wasAborted = true; } if (wasAborted || this.OnOutputSessionClosed()) { Complete(true); } } static void CloseOutputSessionCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState; bool completeSelf = false; Exception completionException = null; try { bool wasAborted = false; try { thisResult.sessionChannel.Session.EndCloseOutputSession(result); } catch (CommunicationObjectAbortedException) { if (thisResult.sessionChannel.State != CommunicationState.Closed) { throw; } completeSelf = true; wasAborted = true; } if (!wasAborted) { completeSelf = thisResult.OnOutputSessionClosed(); } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) throw; completeSelf = true; completionException = e; } if (completeSelf) { thisResult.Complete(false, completionException); } } bool OnOutputSessionClosed() { bool wasAborted = false; Message message = null; bool receivedMessage = false; try { IAsyncResult result = this.sessionChannel.BeginTryReceive(this.timeoutHelper.RemainingTime(), receiveCallback, this); if (!result.CompletedSynchronously) { return false; } receivedMessage = this.sessionChannel.EndTryReceive(result, out message); } catch (CommunicationObjectAbortedException) { if (this.sessionChannel.State != CommunicationState.Closed) { throw; } wasAborted = true; } if (wasAborted) { return true; } if (receivedMessage) { return this.OnMessageReceived(message); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, this.timeoutHelper.OriginalTimeout))); } } static void ReceiveCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState; bool completeSelf = false; Exception completionException = null; try { Message message = null; bool receivedRequest = false; bool wasAborted = false; try { receivedRequest = thisResult.sessionChannel.EndTryReceive(result, out message); } catch (CommunicationObjectAbortedException) { if (thisResult.sessionChannel.State != CommunicationState.Closed) { throw; } completeSelf = true; wasAborted = true; } if (!wasAborted) { if (receivedRequest) { completeSelf = thisResult.OnMessageReceived(message); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, thisResult.timeoutHelper.OriginalTimeout))); } } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) throw; completeSelf = true; completionException = e; } if (completeSelf) { thisResult.Complete(false, completionException); } } bool OnMessageReceived(Message message) { if (message != null) { using (message) { ProtocolException error = ProtocolException.ReceiveShutdownReturnedNonNull(message); throw TraceUtility.ThrowHelperWarning(error, message); } } bool wasAborted = false; bool inputSessionClosed = false; try { IAsyncResult result = this.sessionChannel.inputSessionCloseHandle.BeginWait(this.timeoutHelper.RemainingTime(), inputSessionWaitCallback, this); if (!result.CompletedSynchronously) { return false; } try { this.sessionChannel.inputSessionCloseHandle.EndWait(result); inputSessionClosed = true; } catch (TimeoutException) { inputSessionClosed = false; } } catch (CommunicationObjectAbortedException) { if (this.sessionChannel.State != CommunicationState.Closed) { throw; } wasAborted = true; } if (wasAborted) { return true; } return this.OnInputSessionWaitOver(inputSessionClosed); } static void WaitForInputSessionCloseCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState; bool completeSelf = false; Exception completionException = null; bool inputSessionClosed = false; try { bool wasAborted = false; try { thisResult.sessionChannel.inputSessionCloseHandle.EndWait(result); inputSessionClosed = true; } catch (TimeoutException) { inputSessionClosed = false; } catch (CommunicationObjectAbortedException) { if (thisResult.sessionChannel.State != CommunicationState.Closed) { throw; } wasAborted = true; completeSelf = true; } if (!wasAborted) { completeSelf = thisResult.OnInputSessionWaitOver(inputSessionClosed); } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) throw; completeSelf = true; completionException = e; } if (completeSelf) { thisResult.Complete(false, completionException); } } bool OnInputSessionWaitOver(bool inputSessionClosed) { if (inputSessionClosed) { lock (this.sessionChannel.ThisLock) { if (!(this.sessionChannel.isInputClosed)) { DiagnosticUtility.DebugAssert("Shutdown request was not received."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ShutdownRequestWasNotReceived))); } } bool outputSessionClosed = false; bool wasAborted = false; try { IAsyncResult result = this.sessionChannel.outputSessionCloseHandle.BeginWait(timeoutHelper.RemainingTime(), true, outputSessionWaitCallback, this); if (!result.CompletedSynchronously) { return false; } this.sessionChannel.outputSessionCloseHandle.EndWait(result); outputSessionClosed = true; } catch (CommunicationObjectAbortedException) { if (this.sessionChannel.State != CommunicationState.Closed) throw; wasAborted = true; } catch (TimeoutException) { outputSessionClosed = false; } if (wasAborted) { return true; } else { return this.OnOutputSessionWaitOver(outputSessionClosed); } } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, timeoutHelper.OriginalTimeout))); } } static void WaitForOutputSessionCloseCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState; bool completeSelf = false; Exception completionException = null; bool outputSessionClosed = false; try { bool wasAborted = false; try { thisResult.sessionChannel.outputSessionCloseHandle.EndWait(result); outputSessionClosed = true; } catch (CommunicationObjectAbortedException) { if (thisResult.sessionChannel.State != CommunicationState.Closed) { throw; } wasAborted = true; completeSelf = true; } catch (TimeoutException) { outputSessionClosed = false; } if (!wasAborted) { completeSelf = thisResult.OnOutputSessionWaitOver(outputSessionClosed); } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) throw; completeSelf = true; completionException = e; } if (completeSelf) { thisResult.Complete(false, completionException); } } bool OnOutputSessionWaitOver(bool outputSessionClosed) { if (outputSessionClosed) { IAsyncResult result = this.sessionChannel.BeginCloseCore(this.timeoutHelper.RemainingTime(), closeCoreCallback, this); if (!result.CompletedSynchronously) { return false; } this.sessionChannel.EndCloseCore(result); return true; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseOutputSessionTimeout, timeoutHelper.OriginalTimeout))); } } static void CloseCoreCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseAsyncResult self = (CloseAsyncResult)(result.AsyncState); Exception completionException = null; try { self.sessionChannel.EndCloseCore(result); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) { throw; } completionException = e; } self.Complete(false, completionException); } public static void End(IAsyncResult result) { AsyncResult.End (result); } } class SoapSecurityServerDuplexSession : SoapSecurityInputSession, IDuplexSession { ServerSecurityDuplexSessionChannel channel; public SoapSecurityServerDuplexSession(SecurityContextSecurityToken sessionToken, SecuritySessionServerSettings settings, ServerSecurityDuplexSessionChannel channel) : base(sessionToken, settings, channel) { this.channel = channel; } public void CloseOutputSession() { this.CloseOutputSession(this.channel.DefaultCloseTimeout); } public void CloseOutputSession(TimeSpan timeout) { this.channel.ThrowIfFaulted(); this.channel.ThrowIfNotOpened(); Exception pendingException = null; try { this.channel.CloseOutputSession(timeout); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { throw; } pendingException = e; } if (pendingException != null) { this.channel.Fault(pendingException); if (pendingException is CommunicationException) { throw pendingException; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(pendingException); } } } public IAsyncResult BeginCloseOutputSession(AsyncCallback callback, object state) { return this.BeginCloseOutputSession(this.channel.DefaultCloseTimeout, callback, state); } public IAsyncResult BeginCloseOutputSession(TimeSpan timeout, AsyncCallback callback, object state) { this.channel.ThrowIfFaulted(); this.channel.ThrowIfNotOpened(); Exception pendingException = null; try { return this.channel.BeginCloseOutputSession(timeout, callback, state); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { throw; } pendingException = e; } if (pendingException != null) { this.channel.Fault(pendingException); if (pendingException is CommunicationException) { throw pendingException; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(pendingException); } } return null; } public void EndCloseOutputSession(IAsyncResult result) { Exception pendingException = null; try { this.channel.EndCloseOutputSession(result); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { throw; } pendingException = e; } if (pendingException != null) { this.channel.Fault(pendingException); if (pendingException is CommunicationException) { throw pendingException; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(pendingException); } } } } } internal class SecuritySessionDemuxFailureHandler : IChannelDemuxFailureHandler { SecurityStandardsManager standardsManager; public SecuritySessionDemuxFailureHandler(SecurityStandardsManager standardsManager) { if (standardsManager == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("standardsManager"); } this.standardsManager = standardsManager; } public void HandleDemuxFailure(Message message) { if (message == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message"); } if (DiagnosticUtility.ShouldTraceWarning) { TraceUtility.TraceEvent(System.Diagnostics.TraceEventType.Warning, TraceCode.SecuritySessionDemuxFailure, message); } } public Message CreateSessionDemuxFaultMessage(Message message) { MessageFault fault = SecurityUtils.CreateSecurityContextNotFoundFault(this.standardsManager, message.Headers.Action); Message faultMessage = Message.CreateMessage(message.Version, fault, message.Version.Addressing.DefaultFaultAction); if (message.Headers.MessageId != null) { faultMessage.InitializeReply(message); } return faultMessage; } IAsyncResult BeginHandleDemuxFailure (Message message, TFaultContext faultContext, AsyncCallback callback, object state) { this.HandleDemuxFailure(message); Message fault = CreateSessionDemuxFaultMessage(message); return new SendFaultAsyncResult (fault, faultContext, callback, state); } public IAsyncResult BeginHandleDemuxFailure(Message message, RequestContext faultContext, AsyncCallback callback, object state) { return BeginHandleDemuxFailure (message, faultContext, callback, state); } public IAsyncResult BeginHandleDemuxFailure(Message message, IOutputChannel faultContext, AsyncCallback callback, object state) { return BeginHandleDemuxFailure (message, faultContext, callback, state); } public void EndHandleDemuxFailure(IAsyncResult result) { if (result is SendFaultAsyncResult ) { SendFaultAsyncResult .End(result); } else if (result is SendFaultAsyncResult ) { SendFaultAsyncResult .End(result); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidAsyncResult), "result")); } } class SendFaultAsyncResult : AsyncResult { Message message; static AsyncCallback sendCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(SendCallback)); TFaultContext faultContext; public SendFaultAsyncResult(Message fault, TFaultContext faultContext, AsyncCallback callback, object state) : base(callback, state) { this.faultContext = faultContext; this.message = fault; IAsyncResult result = BeginSend(fault); if (!result.CompletedSynchronously) { return; } EndSend(result); Complete(true); } IAsyncResult BeginSend(Message message) { bool throwing = true; try { IAsyncResult result = null; if (faultContext is RequestContext) { result = ((RequestContext)(object)faultContext).BeginReply(message, sendCallback, this); } else { result = ((IOutputChannel)faultContext).BeginSend(message, sendCallback, this); } throwing = false; return result; } finally { if (throwing && message != null) { message.Close(); } } } void EndSend(IAsyncResult result) { using (this.message) { if (faultContext is RequestContext) { ((RequestContext)(object)faultContext).EndReply(result); } else { ((IOutputChannel)faultContext).EndSend(result); } } } static void SendCallback(IAsyncResult result) { if (result.CompletedSynchronously) { return; } SendFaultAsyncResult self = (SendFaultAsyncResult ) result.AsyncState; Exception completionException = null; try { self.EndSend(result); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Diagnostics.ExceptionUtility.IsFatal(e)) throw; completionException = e; } self.Complete(false, completionException); } internal static void End(IAsyncResult result) { AsyncResult.End >(result); } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- UInt32Storage.cs
- VirtualDirectoryMappingCollection.cs
- HtmlTable.cs
- BamlLocalizableResource.cs
- FileReader.cs
- PageAsyncTaskManager.cs
- _LocalDataStoreMgr.cs
- MILUtilities.cs
- MultiAsyncResult.cs
- DelayDesigner.cs
- SqlInfoMessageEvent.cs
- TextOnlyOutput.cs
- UnescapedXmlDiagnosticData.cs
- DrawingCollection.cs
- HttpCachePolicy.cs
- SourceElementsCollection.cs
- GPPOINTF.cs
- Parser.cs
- CryptoStream.cs
- RequestBringIntoViewEventArgs.cs
- StringUtil.cs
- ValidationEventArgs.cs
- DbConnectionPoolGroup.cs
- StylusCollection.cs
- MonikerBuilder.cs
- WhitespaceRule.cs
- EntityDataSourceSelectedEventArgs.cs
- TraceSection.cs
- SQLInt64Storage.cs
- TransactionInformation.cs
- ProfileEventArgs.cs
- GridSplitterAutomationPeer.cs
- LambdaCompiler.Lambda.cs
- AesCryptoServiceProvider.cs
- SettingsProviderCollection.cs
- ListCommandEventArgs.cs
- _Semaphore.cs
- RequestQueue.cs
- ToolStripPanelSelectionBehavior.cs
- ProxyWebPart.cs
- PresentationUIStyleResources.cs
- XmlSchemaValidationException.cs
- ImplicitInputBrush.cs
- SortQuery.cs
- Privilege.cs
- FixedSOMTable.cs
- EncodingStreamWrapper.cs
- DiffuseMaterial.cs
- LineSegment.cs
- WebPartsPersonalization.cs
- FloaterBaseParagraph.cs
- NonParentingControl.cs
- TextEditorThreadLocalStore.cs
- UnknownBitmapEncoder.cs
- FormViewPageEventArgs.cs
- EncoderExceptionFallback.cs
- UniformGrid.cs
- HorizontalAlignConverter.cs
- PngBitmapEncoder.cs
- MeasureItemEvent.cs
- SQLDoubleStorage.cs
- MapPathBasedVirtualPathProvider.cs
- DataListItemCollection.cs
- PolyBezierSegmentFigureLogic.cs
- GradientBrush.cs
- LogManagementAsyncResult.cs
- ContextProperty.cs
- PageCatalogPart.cs
- SynchronizationFilter.cs
- ToolboxItem.cs
- WindowsGraphics.cs
- WebPartsPersonalization.cs
- SessionStateModule.cs
- ToolBarButton.cs
- SystemTcpConnection.cs
- LinqToSqlWrapper.cs
- PriorityQueue.cs
- JsonEncodingStreamWrapper.cs
- EventPrivateKey.cs
- ScriptingJsonSerializationSection.cs
- ListViewItemMouseHoverEvent.cs
- CompModSwitches.cs
- MonitoringDescriptionAttribute.cs
- LinqExpressionNormalizer.cs
- MasterPageParser.cs
- RoleExceptions.cs
- ObjectStateEntryBaseUpdatableDataRecord.cs
- ListBox.cs
- RC2.cs
- CssClassPropertyAttribute.cs
- DataServiceEntityAttribute.cs
- SqlMetaData.cs
- PenContexts.cs
- Internal.cs
- DirectoryInfo.cs
- DirectoryNotFoundException.cs
- WebPartsSection.cs
- SyndicationDeserializer.cs
- TextPatternIdentifiers.cs
- ReadOnlyDataSource.cs