e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
414 lines
16 KiB
C#
414 lines
16 KiB
C#
//------------------------------------------------------------
|
|
// 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<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
|
|
}
|
|
if (!this.CanBuildChannelFactory<TChannel>(context))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
|
new InvalidOperationException(SR.GetString(SR.ContextBindingElementCannotProvideChannelFactory, typeof(TChannel).ToString())));
|
|
}
|
|
|
|
this.EnsureContextExchangeMechanismCompatibleWithScheme(context);
|
|
this.EnsureContextExchangeMechanismCompatibleWithTransportCookieSetting(context);
|
|
|
|
return new ContextChannelFactory<TChannel>(context, this.ContextExchangeMechanism, this.ClientCallbackAddress, this.ContextManagementEnabled);
|
|
}
|
|
|
|
public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
|
|
}
|
|
if (!this.CanBuildChannelListener<TChannel>(context))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
|
new InvalidOperationException(SR.GetString(SR.ContextBindingElementCannotProvideChannelListener, typeof(TChannel).ToString())));
|
|
}
|
|
|
|
this.EnsureContextExchangeMechanismCompatibleWithScheme(context);
|
|
|
|
return new ContextChannelListener<TChannel>(context, this.ContextExchangeMechanism);
|
|
}
|
|
|
|
public override bool CanBuildChannelFactory<TChannel>(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<TChannel>();
|
|
}
|
|
|
|
public override bool CanBuildChannelListener<TChannel>(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<TChannel>());
|
|
}
|
|
|
|
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<T>(BindingContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
|
|
}
|
|
|
|
if (typeof(T) == typeof(ChannelProtectionRequirements) && this.ProtectionLevel != ProtectionLevel.None)
|
|
{
|
|
ChannelProtectionRequirements innerRequirements = context.GetInnerProperty<ChannelProtectionRequirements>();
|
|
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<ICorrelationDataSource>();
|
|
correlationData = CorrelationDataSourceHelper.Combine(innerCorrelationData, ContextExchangeCorrelationDataDescription.DataSource);
|
|
instanceCorrelationData = correlationData;
|
|
}
|
|
|
|
return (T)(object)correlationData;
|
|
}
|
|
|
|
return context.GetInnerProperty<T>();
|
|
}
|
|
|
|
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<IContextBindingElement>(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; }
|
|
}
|
|
}
|
|
}
|
|
}
|