WWSAPI to WCF interop 11: security binding templates

In my previous post on WsUtil, I explained how the generated helper functions can simplify the creation of WS_SERVICE_PROXY and WS_SERVICE_ENDPOINT. In both of these functions, the first parameter is a pointer to a same binding template. When no security is used in the binding, the template will be a simple wrapper of channel properties (e.g. WS_HTTP_BINDING_TEMPLATE, WS_TCP_BINDING_TEMPLATE), in which case the parameter can be NULL if no channel properties need to be set (pointer to an empty structure will also work). When security is used in the binding, passing NULL or empty structure will not work in cases where the client needs to be authenticated (HTTPS without client certificate being the only exception). This is because the template function requires the client credential to be specified explicitly. Next I’ll give an example of how to fill in a binding template for HTTP Basic header authentication over HTTPS. In this scenario, WsUtil will generate the helper function with the following prototype:

 

HRESULT BasicHttpBinding_ICalculator_CreateServiceProxy(

    __in_opt WS_HTTP_SSL_HEADER_AUTH_BINDING_TEMPLATE* templateValue,

    __in_ecount_opt(proxyPropertyCount) const WS_PROXY_PROPERTY* proxyProperties,

    __in const ULONG proxyPropertyCount,

    __deref_out_opt WS_SERVICE_PROXY** _serviceProxy,

    __in_opt WS_ERROR* error);

struct BasicHttpBinding_ICalculatorFunctionTable;

HRESULT BasicHttpBinding_ICalculator_CreateServiceEndpoint(

    __in_opt WS_HTTP_SSL_HEADER_AUTH_BINDING_TEMPLATE* templateValue,

    __in_opt CONST WS_STRING* address,

    __in_opt struct WSHttpBinding_IChatFunctionTable* functionTable,

    __in_opt WS_SERVICE_SECURITY_CALLBACK authorizationCallback,

    __in_ecount_opt(endpointPropertyCount) WS_SERVICE_ENDPOINT_PROPERTY* endpointProperties,

    __in const ULONG endpointPropertyCount,

    __in WS_HEAP* heap,

    __deref_out_opt WS_SERVICE_ENDPOINT** serviceEndpoint,

    __in_opt WS_ERROR* error);

 

WS_HTTP_SSL_HEADER_AUTH_BINDING_TEMPLATE is defined this way:

 

struct _WS_HTTP_SSL_HEADER_AUTH_BINDING_TEMPLATE {

    WS_CHANNEL_PROPERTIES channelProperties;

    WS_SECURITY_PROPERTIES securityProperties;

    WS_SSL_TRANSPORT_SECURITY_BINDING_TEMPLATE sslTransportSecurityBinding;

    WS_HTTP_HEADER_AUTH_SECURITY_BINDING_TEMPLATE httpHeaderAuthSecurityBinding;

};

struct _WS_SSL_TRANSPORT_SECURITY_BINDING_TEMPLATE {

    WS_SECURITY_BINDING_PROPERTIES securityBindingProperties;

    WS_CERT_CREDENTIAL* localCertCredential;

};

struct _WS_HTTP_HEADER_AUTH_SECURITY_BINDING_TEMPLATE {

    WS_SECURITY_BINDING_PROPERTIES securityBindingProperties;

    WS_WINDOWS_INTEGRATED_AUTH_CREDENTIAL* clientCredential;

};

 

The naming convention of these structures may not be clear at first look, but is actually straightforward. The first parameter of the two helper functions is called a binding template (ending with “_BINDING_TEMPLATE”) – the word “BINDING” corresponds to the wsdl:binding element in the WSDL document (more specifically it corresponds to the extension information – policy extension through wsp:PolicyReference or soap extension through soap:binding – in the wsdl:binding element). The extension information is mainly organized into two parts: the soap extension information and non-security policy information are put into WS_CHANNEL_PROPERTIES, while all the security information into WS_SECURITY_PROPERTIES and structures called security binding templates (ending with “_SECURITY_BINDING_TEMPLATE”).

 

In this scenario, the binding template contains two security binding templates: one for SSL, the other for HTTP header authentication. As I mentioned earlier, the client credential should be explicitly specified. Since we are only using Windows credential for HTTP header authentication, we only need to specify the clientCredential in the WS_HTTP_HEADER_AUTH_SECURITY_BINDING_TEMPLATE (The generated code will contain information on which scheme to use). Here is the code to initialize WS_HTTP_SSL_HEADER_AUTH_BINDING_TEMPLATE:

 

        WS_STRING_WINDOWS_INTEGRATED_AUTH_CREDENTIAL explicitCredential = {

            {WS_STRING_WINDOWS_INTEGRATED_AUTH_CREDENTIAL_TYPE},

            WS_STRING_VALUE(L"FooUser"),

            WS_STRING_VALUE(L"F00Pwd!"),

            WS_STRING_VALUE(L"FooDomain")

        };

        WS_HTTP_SSL_HEADER_AUTH_BINDING_TEMPLATE bindingTemplate = {};

        bindingTemplate.httpHeaderAuthSecurityBinding.clientCredential = &explicitCredential.credential;

 

If the server requires client certificate for SSL, you’ll have to specify it in bindingTemplate.sslTransportSecurityBinding.localCertCredential.

 

Note: the corresponding WCF endpoint uses this binding config:

 

      <basicHttpBinding>

        <binding name="basicWithSsl">

          <security mode="Transport">

            <transport clientCredentialType="Basic" />

          </security>

        </binding>

      </basicHttpBinding>

 

The binding can be created in code as following:

 

BasicHttpBinding basicWithSsl = new BasicHttpBinding(BasicHttpSecurityMode.Transport);

basicWithSsl.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;