268 lines
14 KiB
C#
268 lines
14 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.ServiceModel.Channels
|
|
{
|
|
using System.Xml;
|
|
using System.ServiceModel;
|
|
using System.ServiceModel.Description;
|
|
using System.ServiceModel.Security;
|
|
using System.Xml.Schema;
|
|
using System.Collections.ObjectModel;
|
|
using System.Collections.Generic;
|
|
using WsdlNS = System.Web.Services.Description;
|
|
|
|
// implemented by Indigo Transports
|
|
interface ITransportPolicyImport
|
|
{
|
|
void ImportPolicy(MetadataImporter importer, PolicyConversionContext policyContext);
|
|
}
|
|
|
|
public class TransportBindingElementImporter : IWsdlImportExtension, IPolicyImportExtension
|
|
{
|
|
|
|
void IWsdlImportExtension.BeforeImport(WsdlNS.ServiceDescriptionCollection wsdlDocuments, XmlSchemaSet xmlSchemas, ICollection<XmlElement> policy)
|
|
{
|
|
WsdlImporter.SoapInPolicyWorkaroundHelper.InsertAdHocTransportPolicy(wsdlDocuments);
|
|
}
|
|
|
|
void IWsdlImportExtension.ImportContract(WsdlImporter importer, WsdlContractConversionContext context) { }
|
|
|
|
void IWsdlImportExtension.ImportEndpoint(WsdlImporter importer, WsdlEndpointConversionContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
|
|
}
|
|
|
|
#pragma warning suppress 56506 // [....], these properties cannot be null in this context
|
|
if (context.Endpoint.Binding == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context.Endpoint.Binding");
|
|
}
|
|
|
|
#pragma warning suppress 56506 // [....], CustomBinding.Elements never be null
|
|
TransportBindingElement transportBindingElement = GetBindingElements(context).Find<TransportBindingElement>();
|
|
|
|
bool transportHandledExternaly = (transportBindingElement != null) && !StateHelper.IsRegisteredTransportBindingElement(importer, context);
|
|
if (transportHandledExternaly)
|
|
return;
|
|
|
|
#pragma warning suppress 56506 // [....], these properties cannot be null in this context
|
|
WsdlNS.SoapBinding soapBinding = (WsdlNS.SoapBinding)context.WsdlBinding.Extensions.Find(typeof(WsdlNS.SoapBinding));
|
|
if (soapBinding != null && transportBindingElement == null)
|
|
{
|
|
CreateLegacyTransportBindingElement(importer, soapBinding, context);
|
|
}
|
|
|
|
// Try to import WS-Addressing address from the port
|
|
if (context.WsdlPort != null)
|
|
{
|
|
ImportAddress(context, transportBindingElement);
|
|
}
|
|
|
|
}
|
|
|
|
static BindingElementCollection GetBindingElements(WsdlEndpointConversionContext context)
|
|
{
|
|
Binding binding = context.Endpoint.Binding;
|
|
BindingElementCollection elements = binding is CustomBinding ? ((CustomBinding)binding).Elements : binding.CreateBindingElements();
|
|
return elements;
|
|
}
|
|
|
|
static CustomBinding ConvertToCustomBinding(WsdlEndpointConversionContext context)
|
|
{
|
|
CustomBinding customBinding = context.Endpoint.Binding as CustomBinding;
|
|
if (customBinding == null)
|
|
{
|
|
customBinding = new CustomBinding(context.Endpoint.Binding);
|
|
context.Endpoint.Binding = customBinding;
|
|
}
|
|
return customBinding;
|
|
}
|
|
|
|
static void ImportAddress(WsdlEndpointConversionContext context, TransportBindingElement transportBindingElement)
|
|
{
|
|
EndpointAddress address = context.Endpoint.Address = WsdlImporter.WSAddressingHelper.ImportAddress(context.WsdlPort);
|
|
if (address != null)
|
|
{
|
|
context.Endpoint.Address = address;
|
|
|
|
// Replace the http BE with https BE only if the uri scheme is https and the transport binding element is a HttpTransportBindingElement but not HttpsTransportBindingElement
|
|
if (address.Uri.Scheme == Uri.UriSchemeHttps && transportBindingElement is HttpTransportBindingElement && !(transportBindingElement is HttpsTransportBindingElement))
|
|
{
|
|
BindingElementCollection elements = ConvertToCustomBinding(context).Elements;
|
|
elements.Remove(transportBindingElement);
|
|
elements.Add(CreateHttpsFromHttp(transportBindingElement as HttpTransportBindingElement));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void CreateLegacyTransportBindingElement(WsdlImporter importer, WsdlNS.SoapBinding soapBinding, WsdlEndpointConversionContext context)
|
|
{
|
|
// We create a transportBindingElement based on the SoapBinding's Transport
|
|
TransportBindingElement transportBindingElement = CreateTransportBindingElements(soapBinding.Transport, null);
|
|
if (transportBindingElement != null)
|
|
{
|
|
ConvertToCustomBinding(context).Elements.Add(transportBindingElement);
|
|
StateHelper.RegisterTransportBindingElement(importer, context);
|
|
}
|
|
}
|
|
|
|
static HttpsTransportBindingElement CreateHttpsFromHttp(HttpTransportBindingElement http)
|
|
{
|
|
if (http == null) return new HttpsTransportBindingElement();
|
|
|
|
HttpsTransportBindingElement https = HttpsTransportBindingElement.CreateFromHttpBindingElement(http);
|
|
|
|
return https;
|
|
}
|
|
|
|
void IPolicyImportExtension.ImportPolicy(MetadataImporter importer, PolicyConversionContext policyContext)
|
|
{
|
|
XmlQualifiedName wsdlBindingQName;
|
|
string transportUri = WsdlImporter.SoapInPolicyWorkaroundHelper.FindAdHocTransportPolicy(policyContext, out wsdlBindingQName);
|
|
|
|
if (transportUri != null && !policyContext.BindingElements.Contains(typeof(TransportBindingElement)))
|
|
{
|
|
TransportBindingElement transportBindingElement = CreateTransportBindingElements(transportUri, policyContext);
|
|
|
|
if (transportBindingElement != null)
|
|
{
|
|
ITransportPolicyImport transportPolicyImport = transportBindingElement as ITransportPolicyImport;
|
|
if (transportPolicyImport != null)
|
|
transportPolicyImport.ImportPolicy(importer, policyContext);
|
|
|
|
policyContext.BindingElements.Add(transportBindingElement);
|
|
StateHelper.RegisterTransportBindingElement(importer, wsdlBindingQName);
|
|
}
|
|
}
|
|
}
|
|
|
|
static TransportBindingElement CreateTransportBindingElements(string transportUri, PolicyConversionContext policyContext)
|
|
{
|
|
TransportBindingElement transportBindingElement = null;
|
|
// Try and Create TransportBindingElement
|
|
switch (transportUri)
|
|
{
|
|
case TransportPolicyConstants.HttpTransportUri:
|
|
transportBindingElement = GetHttpTransportBindingElement(policyContext);
|
|
break;
|
|
case TransportPolicyConstants.TcpTransportUri:
|
|
transportBindingElement = new TcpTransportBindingElement();
|
|
break;
|
|
case TransportPolicyConstants.NamedPipeTransportUri:
|
|
transportBindingElement = new NamedPipeTransportBindingElement();
|
|
break;
|
|
case TransportPolicyConstants.MsmqTransportUri:
|
|
transportBindingElement = new MsmqTransportBindingElement();
|
|
break;
|
|
case TransportPolicyConstants.PeerTransportUri:
|
|
#pragma warning disable 0618
|
|
transportBindingElement = new PeerTransportBindingElement();
|
|
#pragma warning restore 0618
|
|
break;
|
|
case TransportPolicyConstants.WebSocketTransportUri:
|
|
HttpTransportBindingElement httpTransport = GetHttpTransportBindingElement(policyContext);
|
|
httpTransport.WebSocketSettings.TransportUsage = WebSocketTransportUsage.Always;
|
|
httpTransport.WebSocketSettings.SubProtocol = WebSocketTransportSettings.SoapSubProtocol;
|
|
transportBindingElement = httpTransport;
|
|
break;
|
|
default:
|
|
// There may be another registered converter that can handle this transport.
|
|
break;
|
|
}
|
|
|
|
return transportBindingElement;
|
|
}
|
|
|
|
static HttpTransportBindingElement GetHttpTransportBindingElement(PolicyConversionContext policyContext)
|
|
{
|
|
if (policyContext != null)
|
|
{
|
|
WSSecurityPolicy sp = null;
|
|
ICollection<XmlElement> policyCollection = policyContext.GetBindingAssertions();
|
|
if (WSSecurityPolicy.TryGetSecurityPolicyDriver(policyCollection, out sp) && sp.ContainsWsspHttpsTokenAssertion(policyCollection))
|
|
{
|
|
HttpsTransportBindingElement httpsBinding = new HttpsTransportBindingElement();
|
|
httpsBinding.MessageSecurityVersion = sp.GetSupportedMessageSecurityVersion(SecurityVersion.WSSecurity11);
|
|
return httpsBinding;
|
|
}
|
|
}
|
|
|
|
return new HttpTransportBindingElement();
|
|
}
|
|
}
|
|
|
|
internal static class StateHelper
|
|
{
|
|
readonly static object StateBagKey = new object();
|
|
|
|
static Dictionary<XmlQualifiedName, XmlQualifiedName> GetGeneratedTransportBindingElements(MetadataImporter importer)
|
|
{
|
|
object retValue;
|
|
if (!importer.State.TryGetValue(StateHelper.StateBagKey, out retValue))
|
|
{
|
|
retValue = new Dictionary<XmlQualifiedName, XmlQualifiedName>();
|
|
importer.State.Add(StateHelper.StateBagKey, retValue);
|
|
}
|
|
return (Dictionary<XmlQualifiedName, XmlQualifiedName>)retValue;
|
|
}
|
|
|
|
internal static void RegisterTransportBindingElement(MetadataImporter importer, XmlQualifiedName wsdlBindingQName)
|
|
{
|
|
GetGeneratedTransportBindingElements(importer)[wsdlBindingQName] = wsdlBindingQName;
|
|
}
|
|
|
|
internal static void RegisterTransportBindingElement(MetadataImporter importer, WsdlEndpointConversionContext context)
|
|
{
|
|
XmlQualifiedName wsdlBindingQName = new XmlQualifiedName(context.WsdlBinding.Name, context.WsdlBinding.ServiceDescription.TargetNamespace);
|
|
GetGeneratedTransportBindingElements(importer)[wsdlBindingQName] = wsdlBindingQName;
|
|
}
|
|
|
|
internal static bool IsRegisteredTransportBindingElement(WsdlImporter importer, WsdlEndpointConversionContext context)
|
|
{
|
|
XmlQualifiedName key = new XmlQualifiedName(context.WsdlBinding.Name, context.WsdlBinding.ServiceDescription.TargetNamespace);
|
|
return GetGeneratedTransportBindingElements(importer).ContainsKey(key);
|
|
}
|
|
}
|
|
|
|
|
|
static class TransportPolicyConstants
|
|
{
|
|
public const string BasicHttpAuthenticationName = "BasicAuthentication";
|
|
public const string CompositeDuplex = "CompositeDuplex";
|
|
public const string CompositeDuplexNamespace = "http://schemas.microsoft.com/net/2006/06/duplex";
|
|
public const string CompositeDuplexPrefix = "cdp";
|
|
public const string DigestHttpAuthenticationName = "DigestAuthentication";
|
|
public const string DotNetFramingNamespace = FramingEncodingString.NamespaceUri + "/policy";
|
|
public const string DotNetFramingPrefix = "msf";
|
|
public const string HttpTransportNamespace = "http://schemas.microsoft.com/ws/06/2004/policy/http";
|
|
public const string HttpTransportPrefix = "http";
|
|
public const string HttpTransportUri = "http://schemas.xmlsoap.org/soap/http";
|
|
public const string MsmqBestEffort = "MsmqBestEffort";
|
|
public const string MsmqSession = "MsmqSession";
|
|
public const string MsmqTransportNamespace = "http://schemas.microsoft.com/ws/06/2004/mspolicy/msmq";
|
|
public const string MsmqTransportPrefix = "msmq";
|
|
public const string MsmqTransportUri = "http://schemas.microsoft.com/soap/msmq";
|
|
public const string MsmqVolatile = "MsmqVolatile";
|
|
public const string MsmqAuthenticated = "Authenticated";
|
|
public const string MsmqWindowsDomain = "WindowsDomain";
|
|
public const string NamedPipeTransportUri = "http://schemas.microsoft.com/soap/named-pipe";
|
|
public const string NegotiateHttpAuthenticationName = "NegotiateAuthentication";
|
|
public const string NtlmHttpAuthenticationName = "NtlmAuthentication";
|
|
public const string PeerTransportUri = "http://schemas.microsoft.com/soap/peer";
|
|
public const string ProtectionLevelName = "ProtectionLevel";
|
|
public const string RequireClientCertificateName = "RequireClientCertificate";
|
|
public const string SslTransportSecurityName = "SslTransportSecurity";
|
|
public const string StreamedName = "Streamed";
|
|
public const string TcpTransportUri = "http://schemas.microsoft.com/soap/tcp";
|
|
public const string WebSocketPolicyPrefix = "mswsp";
|
|
public const string WebSocketPolicyNamespace = "http://schemas.microsoft.com/soap/websocket/policy";
|
|
public const string WebSocketTransportUri = "http://schemas.microsoft.com/soap/websocket";
|
|
public const string WebSocketEnabled = "WebSocketEnabled";
|
|
public const string WindowsTransportSecurityName = "WindowsTransportSecurity";
|
|
}
|
|
}
|