Pingpong
Pingpong

Reputation: 8009

WCF transport security, wsHttpBinding, message security in load balancer

I have a WCF service that uses message security over HTTPS using wsHttpBinding behind load balancer. When connects to the service on web browser via https, it works. However, Windowns forms client failed, using certificate over https,

Update

The request url is https, but after the exception saying http, below is exception tracing on server side:

For example: the request url is

https://www.server.com/wcf.svc'.

But it becomes

http://www.server.com:81/wcf.svc' on the server side. Is it the load balancer causing it.

System.ServiceModel.EndpointNotFoundException, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

There was no channel actively listening at 'http://www.server.com:81/wcf.svc'. This is often caused by an incorrect address URI. Ensure that the address to which the message is sent matches an address on which a service is listening.

Below is the WCF service config:

<system.serviceModel>
    <diagnostics>
      <messageLogging logEntireMessage="true" logMalformedMessages="true"
              logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="false" />
    </diagnostics>
    <services>
      <service behaviorConfiguration="verServiceBehaviour" name="ver.Service">

        <endpoint address="ver" binding="wsHttpBinding" bindingConfiguration="wshttpbindingcfg"             
                   contract="ver.Iver"  behaviorConfiguration ="verEndpointBehaviour">  
        </endpoint>

        <endpoint address="mex" binding="mexHttpBinding" bindingConfiguration="mexhttpbinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="https://www.server.com/" />
          </baseAddresses>
        </host>
      </service>   

    </services>
    <bindings>
      <mexHttpBinding>
        <binding name="mexhttpbinding" />
      </mexHttpBinding>
      <wsHttpBinding>
        <binding name="wshttpbindingcfg" maxReceivedMessageSize="2000000000" sendTimeout="00:10:00">
          <readerQuotas maxStringContentLength="2000000000"/>

          <reliableSession ordered="true" enabled="false" />

            <security mode="None">
                        <transport clientCredentialType="None" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="Certificate" negotiateServiceCredential="true"
                            algorithmSuite="Default" establishSecurityContext="false" />
                    </security>

        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="verEndpointBehaviour">
          <instanceContextBehavior/>
          <verInspectorBehavior/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="verServiceBehaviour">
          <dataContractSerializer maxItemsInObjectGraph="100000000"/>
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />

          <serviceCredentials>
            <clientCertificate>
              <authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck" trustedStoreLocation="LocalMachine" mapClientCertificateToWindowsAccount="false"/>
            </clientCertificate>

                <serviceCertificate
               x509FindType="FindByThumbprint"
               findValue="xxxx"
               storeLocation="LocalMachine"
               storeName="My"/>

          </serviceCredentials>

        </behavior>


      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>

Below is client config:

<configuration>
    <appSettings>
        <add key="CertificateSubjectName" value="subjectName"/>
    </appSettings>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_ver.IverHTTPS" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />

                    <security mode="TransportWithMessageCredential">
                        <transport clientCredentialType="None" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="Certificate" negotiateServiceCredential="true"
                            algorithmSuite="Default" establishSecurityContext="false" />

                    </security>
                </binding>

            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://www.server.com/wcf.svc" 
              binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ver.IverHTTPS"
              contract="ServiceReference.verIver" name="verEndPoint" />


        </client>
    </system.serviceModel>
</configuration>

below is code in client using certificate:

var proxyClient = new ServiceReference.VerIVerClient("verEndPoint");

proxyClient.ClientCredentials.ClientCertificate.SetCertificate(
    System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser,
    System.Security.Cryptography.X509Certificates.StoreName.My,    
    System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName,
    subjectName");                   

proxyClient.CallService()

Below is exception received at client side:

System.ServiceModel.EndpointNotFoundException was unhandled
  Message=There was no endpoint listening at https://ver20.server.com/wcf.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
  Source=mscorlib
  StackTrace:
    Server stack trace: 
       at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
       at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
       at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
       at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
       at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
       at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
       at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
       at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
    Exception rethrown at [0]: 
       at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       at verClient.ServiceReference.verIver.GetClaimver(GetClaimverClaimApplication ClaimApplication)
       at verClient.ServiceReference.verIverClient.GetClaimver(GetClaimverClaimApplication ClaimApplication) in D:\Projects\ver\verClient\Service References\ServiceReference\Reference.cs:line 11330
       at verClient.verForm.PostXmlTover(GetClaimverClaimApplication ClaimApplication) in D:\Projects\ver\verClient\verForm.cs:line 1408
       at verClient.verForm.PostButton_Click(Object sender, EventArgs e) in D:\Projects\ver\verClient\verForm.cs:line 34
       at System.Windows.Forms.Control.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.Button.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(Form mainForm)
       at verClient.Program.Main() in D:\Projects\ver\verClient\Program.cs:line 18
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.Net.WebException
       Message=The remote server returned an error: (404) Not Found.
       Source=System
       StackTrace:
            at System.Net.HttpWebRequest.GetResponse()
            at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
       InnerException: 

Upvotes: 1

Views: 1778

Answers (1)

xtrem
xtrem

Reputation: 1779

Review the configuration of your load balancer, and make sure that the requests are being for warded to the correct host AND PORT number. If the port number you chose is not standard, make sure to adjust the IIS Site Binding and the base address of your service.

One important thing to understand about transport security is that it has to be configured on a "hop" by "hop" basis. In your example, you have two hops (client) -> (load balancer) and (load balancer) -> (server).

Securing your connection from the client to the load balancer doesn't automatically configure security from the load balancer to the server. You need to install and configure an ssl certificate on both the load balancer and the server.

Your initial https request ended up being an http request on the server, that is a good indication that you did not configure a secure channel between the load balancer and the server.

If you do not wish to secure the connection between the load balancer and the server, then expose your service without transport security. With this, you can still have the communication from the client to the load balancer (the first hop) on ssl.

Upvotes: 2

Related Questions