File: CodeDomFixup\EndpointSelector.cs
Web Access
Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Security;
using System.ServiceModel.Security.Tokens;
 
namespace Microsoft.Tools.ServiceModel.Svcutil
{
    internal class EndpointSelector : MetadataFixup
    {
        private static List<string> s_bindingValidationErrors = new List<string>();
 
        public EndpointSelector(WsdlImporter importer, Collection<ServiceEndpoint> endpoints, Collection<Binding> bindings, Collection<ContractDescription> contracts)
            : base(importer, endpoints, bindings, contracts)
        { }
 
        public override void Fixup()
        {
            CollectionHelpers.MapList<ServiceEndpoint>(this.endpoints, EndpointSelector.SelectEndpoint, this.AddWarning);
            bindings.Clear();
            foreach (ServiceEndpoint endpoint in endpoints)
            {
                bindings.Add(endpoint.Binding);
            }
        }
 
        private static bool SelectEndpoint(ServiceEndpoint endpoint)
        {
            return IsBindingSupported(endpoint.Binding);
        }
 
        private static bool IsBindingSupported(Binding binding)
        {
            s_bindingValidationErrors.Clear();
 
            if (!(binding is BasicHttpBinding || binding is NetHttpBinding || binding is WSHttpBinding || binding is NetTcpBinding || binding is WSFederationHttpBinding || binding is NetNamedPipeBinding || binding is CustomBinding))
            {
                s_bindingValidationErrors.Add(string.Format(SR.BindingTypeNotSupportedFormat, binding.GetType().FullName,
                    typeof(BasicHttpBinding).FullName, typeof(NetHttpBinding).FullName, typeof(WSHttpBinding).FullName, typeof(NetTcpBinding).FullName, typeof(CustomBinding).FullName));
            }
            else
            {
                WSHttpBinding wsHttpBinding = binding as WSHttpBinding;
                if (wsHttpBinding != null)
                {
                    if (wsHttpBinding.TransactionFlow)
                    {
                        s_bindingValidationErrors.Add(SR.BindingTransactionFlowNotSupported);
                    }
                    if (wsHttpBinding.Security.Mode == SecurityMode.Message)
                    {
                        s_bindingValidationErrors.Add(string.Format(SRServiceModel.UnsupportedSecuritySetting, "Mode", wsHttpBinding.Security.Mode));
                    }
                }
                else
                {
                    NetTcpBinding netTcpBinding = binding as NetTcpBinding;
                    if (netTcpBinding != null)
                    {
                        if (netTcpBinding.TransactionFlow)
                        {
                            s_bindingValidationErrors.Add(SR.BindingTransactionFlowNotSupported);
                        }
                        if (netTcpBinding.Security.Mode == SecurityMode.Message)
                        {
                            s_bindingValidationErrors.Add(string.Format(SRServiceModel.UnsupportedSecuritySetting, "Mode", netTcpBinding.Security.Mode));
                        }
                    }
                    else
                    {
                        NetHttpBinding netHttpBinding = binding as NetHttpBinding;
                        if (netHttpBinding != null)
                        {
                            if (netHttpBinding.Security.Mode == BasicHttpSecurityMode.Message)
                            {
                                s_bindingValidationErrors.Add(string.Format(SRServiceModel.UnsupportedSecuritySetting, "Mode", netHttpBinding.Security.Mode));
                            }
                        }
                        else
                        {
                            BasicHttpBinding basicHttpBinding = binding as BasicHttpBinding;
                            if (basicHttpBinding != null && basicHttpBinding.Security.Mode == BasicHttpSecurityMode.Message)
                            {
                                s_bindingValidationErrors.Add(string.Format(SRServiceModel.UnsupportedSecuritySetting, "Mode", basicHttpBinding.Security.Mode));
                            }
                            else
                            {
                                WS2007FederationHttpBinding ws2007FederationHttpBinding = binding as WS2007FederationHttpBinding;
                                if (ws2007FederationHttpBinding != null && ws2007FederationHttpBinding.Security.Mode == WSFederationHttpSecurityMode.Message)
                                {
                                    s_bindingValidationErrors.Add(string.Format(SRServiceModel.UnsupportedSecuritySetting, "Mode", ws2007FederationHttpBinding.Security.Mode));
                                }
                                else
                                {
                                    WSFederationHttpBinding wsFederationHttpBinding = binding as WSFederationHttpBinding;
                                    if (wsFederationHttpBinding != null && wsFederationHttpBinding.Security.Mode == WSFederationHttpSecurityMode.Message)
                                    {
                                        s_bindingValidationErrors.Add(string.Format(SRServiceModel.UnsupportedSecuritySetting, "Mode", wsFederationHttpBinding.Security.Mode));
                                    }
                                }
                            }
                        }
                    }
                }
 
                ValidateBindingElements(binding);
            }
 
            return s_bindingValidationErrors.Count == 0;
        }
 
        private static void ValidateBindingElements(Binding binding)
        {
            BindingElementCollection bindingElements = binding.CreateBindingElements();
 
            foreach (BindingElement bindingElement in bindingElements)
            {
                if (bindingElement is TransportBindingElement)
                {
                    if (!(bindingElement is HttpTransportBindingElement || bindingElement is HttpsTransportBindingElement || bindingElement is TcpTransportBindingElement || bindingElement is NamedPipeTransportBindingElement))
                    {
                        s_bindingValidationErrors.Add(string.Format(SR.BindingTransportTypeNotSupportedFormat, bindingElement.GetType().FullName,
                            typeof(HttpTransportBindingElement).FullName, typeof(HttpsTransportBindingElement).FullName, typeof(TcpTransportBindingElement).FullName));
                    }
                }
                else if (bindingElement is MessageEncodingBindingElement)
                {
                    if (!(bindingElement is BinaryMessageEncodingBindingElement || bindingElement is TextMessageEncodingBindingElement || bindingElement is MtomMessageEncodingBindingElement))
                    {
                        s_bindingValidationErrors.Add(string.Format(SR.BindingMessageEncodingElementNotSupportedFormat, bindingElement.GetType().FullName,
                            typeof(BinaryMessageEncodingBindingElement).FullName, typeof(TextMessageEncodingBindingElement).FullName));
                    }
                    else
                    {
                        var binMsgEncodingElement = bindingElement as BinaryMessageEncodingBindingElement;
                        if (binMsgEncodingElement != null)
                        {
                            if (binMsgEncodingElement.MessageVersion != MessageVersion.Soap12WSAddressing10)
                            {
                                s_bindingValidationErrors.Add(string.Format(SR.BindingBinaryMessageEncodingVersionNotSupportedFormat,
                                    binMsgEncodingElement.MessageVersion, MessageVersion.Soap12WSAddressing10));
                            }
                        }
                        else
                        {
                            var txtMsgEncodingElement = bindingElement as TextMessageEncodingBindingElement;
                            if (txtMsgEncodingElement != null &&
                                txtMsgEncodingElement.MessageVersion != MessageVersion.None &&
                                txtMsgEncodingElement.MessageVersion != MessageVersion.Soap11 &&
                                txtMsgEncodingElement.MessageVersion != MessageVersion.Soap12 &&
                                txtMsgEncodingElement.MessageVersion != MessageVersion.Soap11WSAddressing10 &&
                                txtMsgEncodingElement.MessageVersion != MessageVersion.Soap12WSAddressing10)
                            {
                                s_bindingValidationErrors.Add(string.Format(SR.BindingTextMessageEncodingVersionNotSupportedFormat,
                                    txtMsgEncodingElement.MessageVersion,
                                    MessageVersion.None,
                                    MessageVersion.Soap11,
                                    MessageVersion.Soap12,
                                    MessageVersion.Soap11WSAddressing10,
                                    MessageVersion.Soap12WSAddressing10));
                            }
                            else
                            {
                                var mtomMsgEncodingElement = bindingElement as MtomMessageEncodingBindingElement;
                                if (mtomMsgEncodingElement != null &&
                                   mtomMsgEncodingElement.MessageVersion != MessageVersion.Soap11 &&
                                   mtomMsgEncodingElement.MessageVersion != MessageVersion.Soap12 &&
                                   mtomMsgEncodingElement.MessageVersion != MessageVersion.Soap11WSAddressing10 &&
                                   mtomMsgEncodingElement.MessageVersion != MessageVersion.Soap12WSAddressing10)
                                {
                                    s_bindingValidationErrors.Add(string.Format(SR.BindingMtomMessageEncodingVersionNotSupportedFormat,
                                        mtomMsgEncodingElement.MessageVersion,
                                        MessageVersion.Soap11,
                                        MessageVersion.Soap12,
                                        MessageVersion.Soap11WSAddressing10,
                                        MessageVersion.Soap12WSAddressing10));
                                }
                            }
                        }
                    }
                }
                else if (bindingElement is SslStreamSecurityBindingElement)
                {
                    // do nothing
                }
                else if (bindingElement is WindowsStreamSecurityBindingElement)
                {
                    // do nothing
                }
                else if (bindingElement is ReliableSessionBindingElement)
                {
                    // do nothing
                }
                else if (bindingElement is TransactionFlowBindingElement)
                {
                    if (binding is WSHttpBinding && ((WSHttpBinding)binding).TransactionFlow)
                    {
                        s_bindingValidationErrors.Add(SR.BindingTransactionFlowNotSupported);
                    }
                    if (binding is NetTcpBinding && ((NetTcpBinding)binding).TransactionFlow)
                    {
                        s_bindingValidationErrors.Add(SR.BindingTransactionFlowNotSupported);
                    }
                }
                else if (bindingElement is TransportSecurityBindingElement)
                {
                    ValidateTransportSecurityBindingElement(bindingElement as TransportSecurityBindingElement);
                }
                else
                {
                    s_bindingValidationErrors.Add(string.Format(SR.BindingElementTypeNotSupportedFormat, bindingElement.GetType().FullName));
                }
            }
        }
 
        private static void ValidateTransportSecurityBindingElement(TransportSecurityBindingElement transportSecurityBindingElement)
        {
            if (transportSecurityBindingElement.EndpointSupportingTokenParameters.Signed.Count != 0 ||
                transportSecurityBindingElement.EndpointSupportingTokenParameters.SignedEndorsing.Count != 0)
            {
                s_bindingValidationErrors.Add(SR.BindingTransportSecurityTokenSignedOrSignedEndorsingNotSupported);
            }
            else if (transportSecurityBindingElement.EndpointSupportingTokenParameters.SignedEncrypted.Count == 1)
            {
                ValidateUserNamePasswordSecurityBindingElement(transportSecurityBindingElement);
            }
            else if (transportSecurityBindingElement.EndpointSupportingTokenParameters.Endorsing.Count == 1)
            {
                SecureConversationSecurityTokenParameters endorsingTokenParams = transportSecurityBindingElement.EndpointSupportingTokenParameters.Endorsing[0] as SecureConversationSecurityTokenParameters;
 
                if (endorsingTokenParams != null)
                {
                    if (endorsingTokenParams.RequireDerivedKeys)
                    {
                        s_bindingValidationErrors.Add(SR.BindingTransportSecurityTokenParamsRequiringDerivedKeysNotSupported);
                    }
 
                    TransportSecurityBindingElement bootstrapElement = endorsingTokenParams.BootstrapSecurityBindingElement as TransportSecurityBindingElement;
 
                    if (bootstrapElement == null)
                    {
                        s_bindingValidationErrors.Add(string.Format(SR.BindingTransportSecurityElementTypeNotSupportedFormat,
                                            endorsingTokenParams.BootstrapSecurityBindingElement.GetType().FullName, typeof(TransportSecurityBindingElement).FullName));
                    }
                    else
                    {
                        ValidateTransportSecurityBindingElement(bootstrapElement);
                    }
                }
            }
 
            if (!transportSecurityBindingElement.IncludeTimestamp)
            {
                s_bindingValidationErrors.Add(SR.BindingTransportSecurityMustIncludeTimestamp);
            }
 
            if (transportSecurityBindingElement.DefaultAlgorithmSuite != SecurityAlgorithmSuite.Default)
            {
                s_bindingValidationErrors.Add(string.Format(SR.BindingTransportSecurityDefaultAlgorithmSuiteNotSupportedFormat,
                    transportSecurityBindingElement.DefaultAlgorithmSuite.GetType().FullName, SecurityAlgorithmSuite.Default.GetType().FullName));
            }
        }
 
        private static void ValidateUserNamePasswordSecurityBindingElement(TransportSecurityBindingElement transportSecurityBindingElement)
        {
            bool singleSignedEncryptedParam = transportSecurityBindingElement.EndpointSupportingTokenParameters.SignedEncrypted.Count == 1;
            System.Diagnostics.Debug.Assert(singleSignedEncryptedParam, "Unexpected number of SignedEncrypted token parameters in transport security binding!");
 
            if (!singleSignedEncryptedParam)
            {
                return;
            }
 
            if (transportSecurityBindingElement.MessageSecurityVersion != MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10 &&
                transportSecurityBindingElement.MessageSecurityVersion != MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10 &&
                transportSecurityBindingElement.MessageSecurityVersion != MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11 &&
                transportSecurityBindingElement.MessageSecurityVersion != MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10)
            {
                string values = string.Format(CultureInfo.InvariantCulture, "'{0}', '{1}', '{2}'",
                    MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10,
                    MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10,
                    MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11);
 
                s_bindingValidationErrors.Add(string.Format(SR.BindingTransportMessageSecurityVersionNotSupportedFormat, transportSecurityBindingElement.MessageSecurityVersion, values));
            }
 
            if (transportSecurityBindingElement.DefaultAlgorithmSuite != SecurityAlgorithmSuite.Default)
            {
                s_bindingValidationErrors.Add(string.Format(SR.BindingTransportSecurityDefaultAlgorithmSuiteNotSupportedFormat,
                    transportSecurityBindingElement.DefaultAlgorithmSuite.GetType().FullName, SecurityAlgorithmSuite.Default.GetType().FullName));
            }
 
            var userNameParams = transportSecurityBindingElement.EndpointSupportingTokenParameters.SignedEncrypted[0] as UserNameSecurityTokenParameters;
 
            if (userNameParams != null)
            {
                if (userNameParams.InclusionMode != SecurityTokenInclusionMode.AlwaysToRecipient)
                {
                    s_bindingValidationErrors.Add(string.Format(SR.BindingTransportSecurityTokenParamsInclusionModeValueNotSupportedFormat,
                        userNameParams.InclusionMode, SecurityTokenInclusionMode.AlwaysToRecipient));
                }
                if (userNameParams.ReferenceStyle != SecurityTokenReferenceStyle.Internal)
                {
                    s_bindingValidationErrors.Add(string.Format(SR.BindingTransportSecurityTokenParamsReferenceStyleNotSupportedFormat,
                        userNameParams.ReferenceStyle, SecurityTokenReferenceStyle.Internal));
                }
                if (userNameParams.RequireDerivedKeys != false)
                {
                    s_bindingValidationErrors.Add(SR.BindingTransportSecurityTokenParamsRequiringDerivedKeysNotSupported);
                }
            }
            else
            {
                s_bindingValidationErrors.Add(string.Format(SR.BindingTransportSecurityTokenParamsTypeNotSupportedFormat,
                    transportSecurityBindingElement.EndpointSupportingTokenParameters.SignedEncrypted[0].GetType().FullName, typeof(UserNameSecurityTokenParameters).FullName));
            }
        }
 
        private void AddWarning(ServiceEndpoint endpoint, int i)
        {
            MetadataConversionError warning;
 
            foreach (var validationErrorMsg in s_bindingValidationErrors)
            {
                warning = new MetadataConversionError(validationErrorMsg, isWarning: true);
                if (!importer.Errors.Contains(warning))
                {
                    importer.Errors.Add(warning);
                }
            }
 
            string incompatEndpointMsg = string.Format(CultureInfo.InvariantCulture, SR.WrnIncompatibleEndpointFormat, endpoint.Name, endpoint.Address);
 
            warning = new MetadataConversionError(incompatEndpointMsg, isWarning: true);
            if (!importer.Errors.Contains(warning))
            {
                importer.Errors.Add(warning);
            }
        }
    }
}