WWSAPI to WCF interop 6: NetTcpBinding with transport security

NetTcpBinding provides a more efficient way to send/receive SOAP messages than HTTP does. The SOAP envelopes are transferred in binary format and an XML dictionary is built over the TCP session to help further reduce the payload size. NetTcpBinding supports all three security modes (message, transport, mixed) and can be used with no security as well. For transport security, both SSL and Windows SPNEGO are supported. Since SSL over TCP is not supported by WWSAPI in Win7, in this post I’ll focus on how to write a WWSAPI client to communicate with a WCF service using Windows security over TCP.

 

WS_TCP_SSPI_TRANSPORT_SECURITY_BINDING is the binding in WWSAPI for using Windows security over TCP. The following code snippet shows how to use it. Notice that you need to provide a credential even when you want to use the default credential.

 

    WS_DEFAULT_WINDOWS_INTEGRATED_AUTH_CREDENTIAL defaultCred = {};

    defaultCred.credential.credentialType = WS_DEFAULT_WINDOWS_INTEGRATED_AUTH_CREDENTIAL_TYPE;

    WS_SECURITY_BINDING_PROPERTY bindingProperties[1];

    ULONG bindingPropertyCount = 0;

    // Set a binding property to turn off server authentication.

   // Since the default setting is to require server authentication (which means Kerberos has to

    // be used), WsOpenServiceProxy will fail if NTLM is negotiated (as will be the case when

    // client and server are running on the server machine and client uses default credential).

    // In order to achieve server authentication, the client also needs to provide a correct SPN

    // (Service Principal Name). The SPN can be specified in WS_ENDPOINT_ADDRESS's identity field.

    BOOL requireServerAuth = FALSE;

    bindingProperties[bindingPropertyCount].id = WS_SECURITY_BINDING_PROPERTY_REQUIRE_SERVER_AUTH;

    bindingProperties[bindingPropertyCount].value = &requireServerAuth;

    bindingProperties[bindingPropertyCount].valueSize = sizeof(requireServerAuth);

    bindingPropertyCount++;

    WS_TCP_SSPI_TRANSPORT_SECURITY_BINDING sspiBinding = {};

    sspiBinding.binding.bindingType = WS_TCP_SSPI_TRANSPORT_SECURITY_BINDING_TYPE;

    sspiBinding.clientCredential = &defaultCred.credential;

    sspiBinding.binding.properties = bindingProperties; // set the property array

    sspiBinding.binding.propertyCount = bindingPropertyCount; // set the property count

 

    WS_SECURITY_BINDING* bindings[1] = {&sspiBinding.binding};

    WS_SECURITY_DESCRIPTION securityDescription = {};

    securityDescription.securityBindings = bindings;

    securityDescription.securityBindingCount = WsCountOf(bindings);

 

    hr = WsCreateServiceProxy(

            WS_CHANNEL_TYPE_DUPLEX_SESSION,

          WS_TCP_CHANNEL_BINDING,

            &securityDescription,

            NULL,

            0,

            NULL,

            0,

            &serviceProxy,

            error);

 

Note: the corresponding WCF NetTcpBinding object is configured this way:

    NetTcpBinding binding = new NetTcpBinding(SecurityMode.Transport);

    binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;

 

In config file, the element is:

   <netTcpBinding>

        <binding name="windowsSecurity">

            <security mode="Transport">

                <transport clientCredentialType="Windows"/>

            </security>

        </binding>

    </netTcpBinding>