//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Channels { using System; using System.ComponentModel; using System.Net.Security; using System.Runtime.CompilerServices; using System.ServiceModel.Administration; using System.ServiceModel.Description; using System.ServiceModel.Security; [TypeForwardedFrom("System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")] public class ContextBindingElement : BindingElement, IPolicyExportExtension, IContextSessionProvider, IWmiInstanceProvider, IContextBindingElement { internal const ContextExchangeMechanism DefaultContextExchangeMechanism = ContextExchangeMechanism.ContextSoapHeader; internal const bool DefaultContextManagementEnabled = true; internal const ProtectionLevel DefaultProtectionLevel = ProtectionLevel.Sign; ContextExchangeMechanism contextExchangeMechanism; ICorrelationDataSource instanceCorrelationData; bool contextManagementEnabled; ProtectionLevel protectionLevel; public ContextBindingElement() : this(DefaultProtectionLevel, DefaultContextExchangeMechanism, null, DefaultContextManagementEnabled) { // empty } public ContextBindingElement(ProtectionLevel protectionLevel) : this(protectionLevel, DefaultContextExchangeMechanism, null, DefaultContextManagementEnabled) { // empty } public ContextBindingElement(ProtectionLevel protectionLevel, ContextExchangeMechanism contextExchangeMechanism) : this(protectionLevel, contextExchangeMechanism, null, DefaultContextManagementEnabled) { // empty } public ContextBindingElement(ProtectionLevel protectionLevel, ContextExchangeMechanism contextExchangeMechanism, Uri clientCallbackAddress) : this(protectionLevel, contextExchangeMechanism, clientCallbackAddress, DefaultContextManagementEnabled) { // empty } public ContextBindingElement(ProtectionLevel protectionLevel, ContextExchangeMechanism contextExchangeMechanism, Uri clientCallbackAddress, bool contextManagementEnabled) { this.ProtectionLevel = protectionLevel; this.ContextExchangeMechanism = contextExchangeMechanism; this.ClientCallbackAddress = clientCallbackAddress; this.ContextManagementEnabled = contextManagementEnabled; } ContextBindingElement(ContextBindingElement other) : base(other) { this.ProtectionLevel = other.ProtectionLevel; this.ContextExchangeMechanism = other.ContextExchangeMechanism; this.ClientCallbackAddress = other.ClientCallbackAddress; this.ContextManagementEnabled = other.ContextManagementEnabled; } [DefaultValue(null)] public Uri ClientCallbackAddress { get; set; } [DefaultValue(DefaultContextExchangeMechanism)] public ContextExchangeMechanism ContextExchangeMechanism { get { return this.contextExchangeMechanism; } set { if (!ContextExchangeMechanismHelper.IsDefined(value)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value")); } this.contextExchangeMechanism = value; } } [DefaultValue(DefaultContextManagementEnabled)] public bool ContextManagementEnabled { get { return this.contextManagementEnabled; } set { this.contextManagementEnabled = value; } } [DefaultValue(DefaultProtectionLevel)] public ProtectionLevel ProtectionLevel { get { return this.protectionLevel; } set { if (!ProtectionLevelHelper.IsDefined(value)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value")); } this.protectionLevel = value; } } public override IChannelFactory BuildChannelFactory(BindingContext context) { if (context == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); } if (!this.CanBuildChannelFactory(context)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR.GetString(SR.ContextBindingElementCannotProvideChannelFactory, typeof(TChannel).ToString()))); } this.EnsureContextExchangeMechanismCompatibleWithScheme(context); this.EnsureContextExchangeMechanismCompatibleWithTransportCookieSetting(context); return new ContextChannelFactory(context, this.ContextExchangeMechanism, this.ClientCallbackAddress, this.ContextManagementEnabled); } public override IChannelListener BuildChannelListener(BindingContext context) { if (context == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); } if (!this.CanBuildChannelListener(context)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR.GetString(SR.ContextBindingElementCannotProvideChannelListener, typeof(TChannel).ToString()))); } this.EnsureContextExchangeMechanismCompatibleWithScheme(context); return new ContextChannelListener(context, this.ContextExchangeMechanism); } public override bool CanBuildChannelFactory(BindingContext context) { if (context == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); } return (typeof(TChannel) == typeof(IOutputChannel) || typeof(TChannel) == typeof(IOutputSessionChannel) || typeof(TChannel) == typeof(IRequestChannel) || typeof(TChannel) == typeof(IRequestSessionChannel) || (typeof(TChannel) == typeof(IDuplexSessionChannel) && this.ContextExchangeMechanism != ContextExchangeMechanism.HttpCookie)) && context.CanBuildInnerChannelFactory(); } public override bool CanBuildChannelListener(BindingContext context) { if (context == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); } return ((typeof(TChannel) == typeof(IInputChannel) || typeof(TChannel) == typeof(IInputSessionChannel) || typeof(TChannel) == typeof(IReplyChannel) || typeof(TChannel) == typeof(IReplySessionChannel) || (typeof(TChannel) == typeof(IDuplexSessionChannel) && this.ContextExchangeMechanism != ContextExchangeMechanism.HttpCookie)) && context.CanBuildInnerChannelListener()); } public override BindingElement Clone() { return new ContextBindingElement(this); } public virtual void ExportPolicy(MetadataExporter exporter, PolicyConversionContext context) { if (context == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); } ContextBindingElementPolicy.ExportRequireContextAssertion(this, context.GetBindingAssertions()); } public override T GetProperty(BindingContext context) { if (context == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); } if (typeof(T) == typeof(ChannelProtectionRequirements) && this.ProtectionLevel != ProtectionLevel.None) { ChannelProtectionRequirements innerRequirements = context.GetInnerProperty(); if (innerRequirements == null) { return (T)(object)ContextMessageHeader.GetChannelProtectionRequirements(this.ProtectionLevel); } else { ChannelProtectionRequirements requirements = new ChannelProtectionRequirements(innerRequirements); requirements.Add(ContextMessageHeader.GetChannelProtectionRequirements(this.ProtectionLevel)); return (T)(object)requirements; } } else if (typeof(T) == typeof(IContextSessionProvider)) { return (T)(object)this; } else if (typeof(T) == typeof(IContextBindingElement)) { return (T)(object)this; } else if (typeof(T) == typeof(ICorrelationDataSource)) { ICorrelationDataSource correlationData = instanceCorrelationData; if (correlationData == null) { ICorrelationDataSource innerCorrelationData = context.GetInnerProperty(); correlationData = CorrelationDataSourceHelper.Combine(innerCorrelationData, ContextExchangeCorrelationDataDescription.DataSource); instanceCorrelationData = correlationData; } return (T)(object)correlationData; } return context.GetInnerProperty(); } internal override bool IsMatch(BindingElement b) { if (b == null) { return false; } ContextBindingElement other = b as ContextBindingElement; if (other == null) { return false; } if (this.ClientCallbackAddress != other.ClientCallbackAddress) { return false; } if (this.ContextExchangeMechanism != other.ContextExchangeMechanism) { return false; } if (this.ContextManagementEnabled != other.ContextManagementEnabled) { return false; } if (this.ProtectionLevel != other.protectionLevel) { return false; } return true; } void IWmiInstanceProvider.FillInstance(IWmiInstance wmiInstance) { wmiInstance.SetProperty("ProtectionLevel", this.protectionLevel.ToString()); wmiInstance.SetProperty("ContextExchangeMechanism", this.contextExchangeMechanism.ToString()); wmiInstance.SetProperty("ContextManagementEnabled", this.contextManagementEnabled); } string IWmiInstanceProvider.GetInstanceType() { return "ContextBindingElement"; } internal static void ValidateContextBindingElementOnAllEndpointsWithSessionfulContract(ServiceDescription description, IServiceBehavior callingBehavior) { if (description == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("description"); } if (callingBehavior == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("callingBehavior"); } BindingParameterCollection bpc = new BindingParameterCollection(); foreach (ServiceEndpoint endpoint in description.Endpoints) { if (endpoint.Binding != null && endpoint.Contract != null && !endpoint.InternalIsSystemEndpoint(description) && endpoint.Contract.SessionMode != SessionMode.NotAllowed) { if (endpoint.Binding.GetProperty(bpc) == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR.GetString( SR.BehaviorRequiresContextProtocolSupportInBinding, callingBehavior.GetType().Name, endpoint.Name, endpoint.ListenUri.ToString()))); } } } } void EnsureContextExchangeMechanismCompatibleWithScheme(BindingContext context) { if (context.Binding != null && this.contextExchangeMechanism == ContextExchangeMechanism.HttpCookie && !"http".Equals(context.Binding.Scheme, StringComparison.OrdinalIgnoreCase) && !"https".Equals(context.Binding.Scheme, StringComparison.OrdinalIgnoreCase)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException( SR.GetString( SR.HttpCookieContextExchangeMechanismNotCompatibleWithTransportType, context.Binding.Scheme, context.Binding.Namespace, context.Binding.Name))); } } void EnsureContextExchangeMechanismCompatibleWithTransportCookieSetting(BindingContext context) { if (context.Binding != null && this.contextExchangeMechanism == ContextExchangeMechanism.HttpCookie) { foreach (BindingElement bindingElement in context.Binding.Elements) { HttpTransportBindingElement http = bindingElement as HttpTransportBindingElement; if (http != null && http.AllowCookies) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException( SR.GetString( SR.HttpCookieContextExchangeMechanismNotCompatibleWithTransportCookieSetting, context.Binding.Namespace, context.Binding.Name))); } } } } class ContextExchangeCorrelationDataDescription : CorrelationDataDescription { static CorrelationDataSourceHelper cachedCorrelationDataSource; ContextExchangeCorrelationDataDescription() { } public static ICorrelationDataSource DataSource { get { if (cachedCorrelationDataSource == null) { cachedCorrelationDataSource = new CorrelationDataSourceHelper( new CorrelationDataDescription[] { new ContextExchangeCorrelationDataDescription() }); } return cachedCorrelationDataSource; } } public override bool IsOptional { get { return true; } } public override bool IsDefault { get { return true; } } public override bool KnownBeforeSend { get { return true; } } public override string Name { get { return ContextExchangeCorrelationHelper.CorrelationName; } } public override bool ReceiveValue { get { return true; } } public override bool SendValue { get { return true; } } } } }