WWSAPI to WCF Interop 7: HTTP header authentication (part 2) - used in WSHttpBinding with transport security

In WCF’s standard bindings, HTTP header authentication can be used in WSHttpBinding with security mode Transport. In this security mode, the client credential type can be set to either Basic, Digest, Ntlm or Windows (Negotiate scheme) to enable HTTP header authentication. In this post, I'll use Windows client credential type. In order to communicate with such a WCF endpoint, the WWSAPI client should use a security description with two bindings: WS_SSL_TRANSPORT_SECURITY_BINDING and WS_HTTP_HEADER_AUTH_SECURITY_BINDING; and the authentication scheme should be Negotiate, as shown below:

 

    // declare and initialize an SSL transport security binding

    WS_SSL_TRANSPORT_SECURITY_BINDING sslBinding = {}; // zero out the struct

    sslBinding.binding.bindingType = WS_SSL_TRANSPORT_SECURITY_BINDING_TYPE; // set the binding type

   

    // use the default client credential – if the thread opening the channel/proxy is impersonating,

    // the thread token will be used; otherwise, the process token will be used

    WS_DEFAULT_WINDOWS_INTEGRATED_AUTH_CREDENTIAL defaultCred = {}; // zero out the struct

    defaultCred.credential.credentialType = WS_DEFAULT_WINDOWS_INTEGRATED_AUTH_CREDENTIAL_TYPE;

    // declare and initialize properties to set the authentication scheme to Negotiate

    // Since the default scheme for WWSAPI header authentication is Negotiate, this property

    // may be omitted.

    ULONG scheme = WS_HTTP_HEADER_AUTH_SCHEME_NEGOTIATE;

    WS_SECURITY_BINDING_PROPERTY headerAuthBindingProperties [1] =

    {

        { WS_SECURITY_BINDING_PROPERTY_HTTP_HEADER_AUTH_SCHEME, &scheme, sizeof(scheme) }

    };

    // declare and initialize an header authentication security binding

    WS_HTTP_HEADER_AUTH_SECURITY_BINDING headerAuthBinding = {}; // zero out the struct

    headerAuthBinding.binding.bindingType = WS_HTTP_HEADER_AUTH_SECURITY_BINDING_TYPE;

    headerAuthBinding.binding.properties = headerAuthBindingProperties;

    headerAuthBinding.binding.propertyCount = WsCountOf(headerAuthBindingProperties);

    headerAuthBinding.clientCredential = &defaultCred.credential;

    // declare and initialize the array of all security bindings

    WS_SECURITY_BINDING* securityBindings[2] = { &sslBinding.binding, &headerAuthBinding.binding };

   

    // declare and initialize the security description

    WS_SECURITY_DESCRIPTION securityDescription = {}; // zero out the struct

    securityDescription.securityBindings = securityBindings;

    securityDescription.securityBindingCount = WsCountOf(securityBindings);

 

Then you can create the service proxy with the security description (no channel properties are necessary for this scenario):

    // Create the proxy

    hr = WsCreateServiceProxy(

            WS_CHANNEL_TYPE_REQUEST,

            WS_HTTP_CHANNEL_BINDING,

            (const WS_SECURITY_DESCRIPTION*)&securityDescription, // security description

            NULL, // proxy properties

            0, // proxy property count

NULL , // channel properties

0 , // channel property count

            &proxy,

            error);

Note: the corresponding WSHttpBinding object can be created by the following code:

    WSHttpBinding binding = new WSHttpBinding(SecurityMode.Transport);

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

It can also be represented by the following binding element in config:

     <wsHttpBinding>

       <binding name="HeaderAuth">

          <security mode="Transport">

             <transport clientCredentialType="Windows" />

           </security>

         </binding>

      </wsHttpBinding>