Adding SOAP:HEADER username and password with WSE 3.0
c#, web-services, ws-security, wse3.0
Solution
Got it working, unfortunately before reading wsanville's great answer.
To help others, I'm posting all the steps I needed to do to get it working with Visual Studio 2005:
- Install WSE 3.0, choose custom and select everything
- Read Implementing direct authentication with username token in WSE 3.0 for hints
- Relaunch Visual Studio 2005, now right-click on your project in the solution explorer, and you should have a WSE Settings 3.0 menu item and use that if you want to.
- Update your web references, this should create a new HTTP web service proxy class, with a different name, e.g. `YourWsNameHttpServiceWse`. This is essentially the same as running wsewsdl3.exe
- Use this new class, and you should have access to WSE methods and properties, such as `SetClientCredential`.
I ended up doing almost everything in code, instead of relying on the config-files that are built with my C# DLL. The code ended up looking like this:
FooBarHttpServiceWse wse = new FooBarHttpServiceWse();
wse.SetClientCredential(new UsernameToken(
"username",
"password",
PasswordOption.SendPlainText));
wse.SetPolicy(new FooBarPolicy());
wse.CallSomeServerFunction(yourRequest)
I created my own policy, which looked like this:
using Microsoft.Web.Services3.Design;
// ...
public class FooBarPolicy : Policy
{
public FooBarPolicy()
{
this.Assertions.Add(new UsernameOverTransportAssertion());
}
}
Finally, the WebSphere server responded that A required header representing a Message Addressing Property is not present, and inspecting the outgoing message (using the nice tool Fiddler) I saw the SOAP fault from the server indicated that the Action header was missing.
I tried in vain to set the `wsa:Action` element myself:
using Microsoft.Web.Services3.Addressing;
// ...
wse.RequestSoapContext.Addressing.Action = new Action("CallSomeServerFunction");
The problem was that even if I set an action, when it was sent over the wire, it was empty. Turned out I had to open the WSE proxy class and edit an attribute there:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute(
"---Edit this to set wsa:Action---",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)]
// ...
public SomeServerFunction(...)
After that, it all worked out nicely.
Problem
I have successfully created a WS client that works correctly when NOT using authentication. However, the server (WebSphere) now requires adding a ws-security username token, and I'm having a hard time doing this. The resulting SOAP message is supposed to look something like this: ``` <soapenv:Envelope xmlns:ns="http://foo.bar/1.0" xmlns:ns1="http://www.witsml.org/schemas/140" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header> <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken wsu:Id="UsernameToken-2" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <wsse:Username>foo</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">bar</wsse:Password> <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">foooooobar==</wsse:Nonce> <wsu:Created>2010-01-25T13:09:24.860Z</wsu:Created> </wsse:UsernameToken> </wsse:Security> </soapenv:Header> <soapenv:Body> <ns:fooBar>...</ns:fooBar> </soapenv:Body> ``` I've downloaded and installed Microsoft's WSE 3.0 SDK and added a reference to the DLL in my Visual Studio 2005 project. I now have access to the Microsoft.Web.Services3.* namespaces, but I'm currently stumped on how to proceed. The client code has been generated automatically by a web reference, so I only do a minor amount of work to send the message to the server unauthenticated: ``` WS.FooResultHttpService ws = new WS.FooResultHttpService(); ws.Url = "http://foo.bar.baz"; ws.SendSomething(message); ``` I've just begun to investigate using `Microsoft.Web.Services3.Security.Tokens.UsernameTokenManager`, but so far I haven't been able to get anything up and running. Any hints would be greatly appreciated, as I can't seem to find any good recipes on the net. Thanks!