Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clueless about how to create SOAP <wsse:Security> header

Tags:

c#

.net

soap

I'm have near to none experience with SOAP protocol. The service I need to connect to required header. I think this is somewhat standard in Java but in C# one must create this header by hand.

Does anyone here been able to connect to similar service: have created the header or maybe even know about some standard library which would simplify creation of header? Can you share some code or references?

I also found a clue that maybe header will be generated if using WS2005, because there is WS3 addin for it. Can anybody comment this? After quick look at this addin I found simmilar fields as in Security header, but still wasn't able to create the header.

like image 916
Sergej Andrejev Avatar asked Apr 09 '09 13:04

Sergej Andrejev


People also ask

How do I pass a user ID and password in SOAP header?

ClientCridentials. UserName. Password = "testPass"; In this way you can pass username, password in the header to a SOAP WCF Service.

What is Wsse authentication?

The basic premise of WSSE is that a request header is checked for encrypted credentials, verified using a timestamp and nonce, and authenticated for the requested user using a password digest. It is implemented by the OroWsseAuthenticationBundle that covers most cases from the WSSE specification (PDF).

What is nonce in SOAP header?

Nonce is a randomly-generated, cryptographic token that is used to prevent replay attacks. Although nonce can be inserted anywhere in the SOAP message, it is typically inserted in the <UsernameToken> element.


2 Answers

We were able to solve it with the following code:

public class SecurityHeader : System.ServiceModel.Channels.MessageHeader {
    public string userName;
    public string password;

    protected override void OnWriteStartHeader (System.Xml.XmlDictionaryWriter writer, System.ServiceModel.Channels.MessageVersion messageVersion)
    {
        writer.WriteStartElement("wsse", Name, Namespace);
        writer.WriteXmlnsAttribute("wsse", Namespace);
    }

    protected override void OnWriteHeaderContents (System.Xml.XmlDictionaryWriter writer, System.ServiceModel.Channels.MessageVersion messageVersion)
    {
        writer.WriteStartElement("wsse", "UsernameToken", Namespace);

        writer.WriteStartElement("wsse", "Username", Namespace);
        writer.WriteValue(userName);
        writer.WriteEndElement();

        writer.WriteStartElement("wsse", "Password", Namespace);
        writer.WriteValue(password);
        writer.WriteEndElement();

        writer.WriteEndElement();

    }

    public override string Name
    {
        get { return "Security"; }
    }

    public override string Namespace
    {
        get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
    }
}

This wrote the header that was required by the DataPower box.

How to use the class SecurityHeader

    public static void Main(string[] args)
    {

        var webService = new ServiceReference1.MyWebService();
        ....
       webService.Open();


        using (OperationContextScope scope = new OperationContextScope((IContextChannel)webService.InnerChannel))
        {

            var myObjRequest = GetMyObjRequest();

            MessageHeaders messageHeadersElement = OperationContext.Current.OutgoingMessageHeaders;
            messageHeadersElement.Add(SecurityHeader("UserName", "Password"))


             var res = webService.MyServe(myObjRequest);
            Console.WriteLine(res.ToString());
        }
    }
like image 188
David Avatar answered Nov 10 '22 00:11

David


Funny you should mention that - I've been doing exactly that recently.

I've managed to do it using a SoapExtension which uses ChainStream to keep a copy of the original stream, just copies the stream during BeforeDeserialize and adds the header during AfterSerialize.

Adding the header is a case of reading the contents of the "new" stream (returned from ChainStream) into an XML document (XDocument in my case), adding the header, and then writing it to the original stream passed into ChainStream.

Unfortunately this is pretty dirty, and you can't (as far as I'm aware) use a new instance with appropriate authentication information when you need to.

I've got most of the way using a SoapHeader instead, adding an appropriate attribute to each method of the web service and also an appropriate field/property with an instance of the required header - but the SOAP serialization is currently giving me headaches in terms of specifying the right element names (with namespaces). It's something I've been planning to ask others about when I get the time.

Sorry not to be able to give you a full answer - and also apologies for the lack of code, it belonging to the company rather than me - but hopefully it'll at least give you a starting point.

like image 44
Jon Skeet Avatar answered Nov 10 '22 00:11

Jon Skeet