Saturday, November 24, 2012

WCF client to java web service with username token, timestamp and nonce

I was trying to call a java web service that is implementing username token
My first attempt to call the service, I was getting errors about missing username and password
I followed the steps in several articles online to add it like below
client.ClientCredentials.UserName.UserName = "username";
client.ClientCredentials.UserName.Password = "password";
doing so, I was getting another error about missing timestamp
I followed some other steps from another article  here to add it
#region Begin Magic
BindingElementCollection elements = bean.Endpoint.Binding.CreateBindingElements();
elements.Find<SecurityBindingElement>().IncludeTimestamp = true;
bean.Endpoint.Binding = new CustomBinding(elements);
#endregion
Still I was getting errors
Lastly i found very useful information here and here
I downloaded the sample code from MSDN blog, from this link
Then I used 2 projects from this sample code, the Common project, and the UsernameTokenLibrary, called the java service as exactly in the client project
                Binding userNameBinding = BindingHelper.userNameBinding();
                EndpointAddress serviceAddress = new EndpointAddress("http://localhost/servicemodelsamples/service.svc");

                // Create a client with given client endpoint configuration
                channelFactory = new ChannelFactory<IEchoService>(userNameBinding, serviceAddress);

                // configure the username credentials on the channel factory 
                UsernameClientCredentials credentials = new UsernameClientCredentials(new UsernameInfo("User1", "P@ssw0rd"));

                // replace ClientCredentials with UsernameClientCredentials
                channelFactory.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
                channelFactory.Endpoint.Behaviors.Add(credentials);

                client = channelFactory.CreateChannel();


Doing that, I was getting another error this time “PasswordDigest was supplied, but only http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText is supported”

I then modified the code little bit to send password instead of password digest, in the function WriteTokenCore in UsernameSecurityTokenSerializer.cs in UsernameTokenLibrary project

Commented the lines that writes the password digest

writer.WriteStartElement(Constants.UsernameTokenPrefix, Constants.PasswordElementName, Constants.UsernameTokenNamespace);
writer.WriteAttributeString(Constants.TypeAttributeName, Constants.PasswordDigestType);
writer.WriteValue(c.GetPasswordDigestAsBase64());
writer.WriteEndElement();

And added new line to write the password

so the code would look like this

                writer.WriteStartElement(Constants.UsernameTokenPrefix, Constants.UsernameTokenName, Constants.UsernameTokenNamespace);
                writer.WriteAttributeString(Constants.WsUtilityPrefix, Constants.IdAttributeName, Constants.WsUtilityNamespace, token.Id);
                writer.WriteElementString(Constants.UsernameElementName, Constants.UsernameTokenNamespace, c.UsernameInfo.Username);
                writer.WriteElementString(Constants.PasswordElementName, Constants.UsernameTokenNamespace, c.UsernameInfo.Password);
                writer.WriteElementString(Constants.NonceElementName, Constants.UsernameTokenNamespace, c.GetNonceAsBase64());
                writer.WriteElementString(Constants.CreatedElementName, Constants.WsUtilityNamespace, c.GetCreatedAsString());
                writer.WriteEndElement();

After doing the above modifications, I was able to call the java web service successfully complying with username token