WWSAPI to WCF interop 4: WSHttpBinding with username over transport security
WWSAPI doesn’t support full message mode security (where security negotiation happens at SOAP message level and parts of the envelope are signed and encrypted using XML signature and XML encryption) in Win7 time frame. This means the default WSHttpBinding is not interoperable with the WWSAPI’s security offering as the WSHttpBinding defaults to use full message mode security with secure conversation. WWSAPI supports mixed mode security that provides message integrity and confidentiality at transport level (e.g. through https). In mixed mode security, the client is authenticated through a token carried in the SOAP message’s security header. Client credential types supported by WWSAPI in Win7 include username/password token and Kerberos AP-REQ token. Now I’ll show how to use username/password token over https transport.
As explained in my previous post, WS_SECURITY_DESCRIPTION contains security bindings that describe the security mechanism to be applied to the message or channel. For https, you need to use WS_SSL_TRANSPORT_SECURITY_BINDING. To use username/password token on top of it, WS_USERNAME_MESSAGE_SECURITY_BINDING needs to be included as well. Inside WS_USERNAME_MESSAGE_SECURITY_BINDING, the binding usage should be WS_SUPPORTING_MESSAGE_SECURITY_USAGE, which means the binding is for client authentication only, not message protection. Then a username/password credential needs to be set in the binding so that it could be included in the messages. Here is how the WS_SECURITY_DESCRIPTION can be filled for this scenario.
// declare and initialize a username credential
WS_STRING_USERNAME_CREDENTIAL usernameCredential = {}; // zero out the struct
WS_STRING userName = WS_STRING_VALUE(L"usr1");
WS_STRING passWord = WS_STRING_VALUE(L"pwd1");
usernameCredential.credential.credentialType = WS_STRING_USERNAME_CREDENTIAL_TYPE; // set the credential type
usernameCredential.username = userName;
usernameCredential.password = passWord;
// declare and initialize a username message security binding
WS_USERNAME_MESSAGE_SECURITY_BINDING usernameBinding = {}; // zero out the struct
usernameBinding.binding.bindingType = WS_USERNAME_MESSAGE_SECURITY_BINDING_TYPE; // set the binding type
usernameBinding.bindingUsage = WS_SUPPORTING_MESSAGE_SECURITY_USAGE; // set the binding usage
usernameBinding.clientCredential = &usernameCredential.credential;
// 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
// declare and initialize the array of all security bindings
WS_SECURITY_BINDING* securityBindings[2] = { &sslBinding.binding, &usernameBinding.binding };
// declare and initialize the security description
WS_SECURITY_DESCRIPTION securityDescription = {}; // zero out the struct
securityDescription.securityBindings = securityBindings;
securityDescription.securityBindingCount = WsCountOf(securityBindings);
Then you pass the WS_SECURITY_DESCRIPTION structure to WsCreateServiceProxy:
// Create the proxy
hr = WsCreateServiceProxy(
WS_CHANNEL_TYPE_REQUEST,
WS_HTTP_CHANNEL_BINDING,
&securityDescription, // security description
NULL, // proxy properties
0, // proxy property count
NULL, // channel properties
0, // channel property count
&proxy,
error);
if (FAILED(hr))
{
goto Exit;
}
Note: the corresponding WSHttpBinding object is created this way:
WSHttpBinding binding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential);
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.NegotiateServiceCredential = false;
In config file, it’s presented in the following element:
<wsHttpBinding>
<binding name="UPOverHttps">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" negotiateServiceCredential="false" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
Comments
Anonymous
November 18, 2008
PingBack from http://mstechnews.info/2008/11/wwsapi-to-wcf-interop-4-wshttpbinding-with-username-over-transport-security/Anonymous
February 18, 2009
Several developers have asked me this question and I have decided to create one blog post with the answer.Anonymous
April 06, 2009
Below you may links to resources available for connecting C/C++ code and Web Services using Windows Web