SOAP Header Name space - c#

Service expecting
POST /ADNHContact.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://www.xxx-xxx.co.uk/ADNIntegration/SaveGrantApplication"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<Action xmlns="http://www.xxx-xxx.co.uk/ADNIntegration/" />
</soap:Header>
<soap:Body>
<SaveGrantApplication xmlns="http://www.xxx-xxx.co.uk/ADNIntegration/" />
</soap:Body>
</soap:Envelope>
C# Code for service
public class Action : SoapHeader
{
string somestring;
}
[WebService(Namespace = "http://www.xxx-xxx.co.uk/Integration/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class ADNHContact : System.Web.Services.WebService
{
public Action AppHeader;
[SoapHeader("AppHeader")]
[WebMethod(Description = "AppHeader testing")]
public Compny[] SaveApplication()
{
Compny[] comp = new Compny[] {
new Compny()
{ companyID="C123",companyName="ddd"}
};
return comp;
}
But I want to change the header to this.
<soap:Header>
<Action xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">
http://www.xxx-xxx.co.uk/ADNIntegration/SaveGrantApplication</Action>
</soap:Header>

Related

How to generate UsernameToken for WS-Security?

I have some web service (wrote in Java) and I need create client for it in .NET. The WebService has WS-Security and need PasswordDigest.
First of all, I've tested it in SoapUI and it's works for:
POST http://192.168.100.101:8181/services/ws/SomeService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/soap+xml;charset=UTF-8;action="someMethod"
Content-Length: 971
Host: 192.168.100.101:8181
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
<soap:Envelope xmlns:not="http://existing-domain.com/op/integration/services" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-2C1E2DE2B61EBB94E115572099598331">
<wsse:Username>SOME_LOGIN</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">rcSb6Hd8btcI9g6JvO7dGdiTBTI=</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">PCoVwJm9oEXtusx6gkMb7w==</wsse:Nonce>
<wsu:Created>2019-05-07T06:19:19.824Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body>
<not:someMethod/>
</soap:Body>
</soap:Envelope>
In the next step I've prepared simple client in .NET and check with Wireshark what it sends:
POST /services/ws/SomeService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/soap+xml;charset=UTF-8;action="someMethod"
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Host: 192.168.100.101:8181
Content-Length: 1124
Expect: 100-continue
Connection: Keep-Alive
<soap:Envelope xmlns:not="http://existing-domain.com/op/integration/services" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-85707168-b5c6-47dc-93e9-45afa466fa2a" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>SOME_LOGIN</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">g112a9eHPR1hXD4UH+Lh3o8JV/o=</wsse:Password>
<wsse:Nonce>EiUbo2DbXMGhM26fT+ZkJQ==</wsse:Nonce>
<wsu:Created>2019-05-07T06:27:59Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body>
<not:someMethod />
</soap:Body>
</soap:Envelope>
Unfortunatelly I allways got 500 status code and response:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<soap:Fault>
<soap:Code>
<soap:Value>soap:Sender</soap:Value>
<soap:Subcode>
<soap:Value xmlns:ns1="http://ws.apache.org/wss4j">ns1:SecurityError</soap:Value>
</soap:Subcode>
</soap:Code>
<soap:Reason>
<soap:Text xml:lang="en">A security error was encountered when verifying the message</soap:Text>
</soap:Reason>
</soap:Fault>
</soap:Body>
</soap:Envelope>
I'm pretty sure it's appear because of authorization problem (I had same message in SoapUI if provided wrong credentials).
The section in my client is created with:
UsernameToken t = new UsernameToken("SOME_LOGIN", "SOME_PASSWORD", PasswordOption.SendHashed);
string usernameTokenSection = t.GetXml(new XmlDocument()).OuterXml.ToString();
There is a few articels how to create PasswordDigits (Base64( SHA1(password + nonce + created) )), Nonce (Base64(RandomString)) or Created date but I can't find what is wsu:Id="UsernameToken-2C1E2DE2B61EBB94E115572099598331" and how to create it. Above code where I get xml from UsernameToken returns complete section so I decided to use it, but I noticed that it append wsu:Id="SecurityToken-85707168-b5c6-47dc-93e9-45afa466fa2a" (instead of wsu:Id="UsernameToken-2C1E2DE2B61EBB94E115572099598331"). I can change the name and remove - characters but it's nothing changed and I still get 500 Internal Server Error with message "A security error was encountered when verifying the message".
So, my question is how to generate UsernameToken section with proper wsu:Id="UsernameToken-XXXXXXXXXXXXXXX"data? What is it - just random string or some hash created based on username and password?
Got it! I noticed that SOAP sent from .NET client doesn't have attribute EncodingType in Nonce node. After little modification in code:
UsernameToken t = new UsernameToken("SOME_LOGIN", "SOME_PASSWORD", PasswordOption.SendHashed);
string usernameTokenSection = t.GetXml(new XmlDocument()).OuterXml.ToString().Replace("<wsse:Nonce", "<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\"");
Everything works!
Whole code for .NET client:
public static void Execute()
{
UsernameToken usernameTokenSection = new UsernameToken("SOME_LOGIN", "SOME_PASSWORD", PasswordOption.SendHashed);
HttpWebRequest request = CreateWebRequest();
XmlDocument soapEnvelopeXml = new XmlDocument();
soapEnvelopeXml.LoadXml(#"<soap:Envelope xmlns:not=""http://existing-domain.com/op/integration/services"" xmlns:soap=""http://www.w3.org/2003/05/soap-envelope"">" +
"<soap:Header>" +
#"<wsse:Security xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" xmlns:wsu=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"">"+
usernameTokenSection.GetXml(new XmlDocument()).OuterXml.ToString().Replace("<wsse:Nonce", "<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\"") +
"</wsse:Security>" +
"</soap:Header>"+
"<soap:Body>"+
"<not:someMethod/>"+
"</soap:Body>"+
"</soap:Envelope>");
using (Stream stream = request.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
using (WebResponse response = request.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
string soapResult = rd.ReadToEnd();
Console.WriteLine(soapResult);
}
}
}
public static HttpWebRequest CreateWebRequest()
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(#"http://192.168.100.101:8181/services/ws/SomeService");
webRequest.Method = "POST";
webRequest.Headers.Add("Accept-Encoding:gzip,deflate");
webRequest.ContentType = "application/soap+xml;charset=UTF-8;action=\"someMethod\"";
//NOTE: below it's not necessary
//webRequest.Host = "192.168.100.101:8181";
//webRequest.KeepAlive = true;
//webRequest.UserAgent = "Apache-HttpClient/4.1.1 (java 1.5)";
return webRequest;
}
static void Main(string[] args)
{
try
{
Execute();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.ReadLine();
}
}
PS. For using UsernameToken class you have to using Microsoft.Web.Services2 reference, you can add it by Nuget from here: Microsoft.Web.Services2
PPS. I know that there is simpler way by Add Service Reference... but it require additional classes and modifications for creating Security node in Header, so I decided to send raw xml and manipulate it directly.

Consume Web Service with soap:mustUnderstand attribute

This is my sample Code for Web service. I'm new to SOAP application if someone can spot any problem here it's much appreciated. This error only happened if mustUnderstand attribute ="1"
[WebService(Namespace = "http://www.xxxx.co.uk/Integration/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class ADNHeaderContact : System.Web.Services.WebService
{
public MyHeader myHeader;
[WebMethod]
[SoapHeader("myHeader")]
public string HelloWorld()
{
XmlDocument xmlSoapRequest = new XmlDocument();
using (Stream receiveStream = HttpContext.Current.Request.InputStream)
{
receiveStream.Position = 0;
using (StreamReader readStream =
new StreamReader(receiveStream, Encoding.UTF8))
{
xmlSoapRequest.Load(readStream);
}
}
using (XmlBreaker readxml = new XmlBreaker())
{
using (ReponseSaveApplications respose = new ReponseSaveApplications())
{
return ("Hello");
}
};
}
}
My Postman post request
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<MyHeader soap:mustUnderstand="true" xmlns="http:www.xxxx.co.uk/Integration/">
<MyValue>string</MyValue>
</MyHeader>
</soap:Header
<soap:Body>
<HelloWorld xmlns="http://www.xxxx.co.uk/Integration/" />
</soap:Body>
</soap:Envelope>
My Postman post response
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<soap:Fault>
<faultcode>soap:MustUnderstand</faultcode>
<faultstring>System.Web.Services.Protocols.SoapHeaderException: SOAP header MyHeader was not understood.
at System.Web.Services.Protocols.SoapHeaderHandling.SetHeaderMembers(SoapHeaderCollection headers, Object target, SoapHeaderMapping[] mappings, SoapHeaderDirection direction, Boolean client)
at System.Web.Services.Protocols.SoapServerProtocol.CreateServerInstance()
at System.Web.Services.Protocols.WebServiceHandler.Invoke()
at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
SoapHeader.MustUnderstand Property
When an XML Web service client adds a SOAP header to an XML Web
service method call with the MustUnderstand property set to true, the
XML Web service method must set the DidUnderstand property to true;
otherwise, a SoapHeaderException is thrown back to the XML Web service
client by ASP.NET.

WCF Service XML Serialization

I have written a WCF Service. below is my code.
[XmlArrayItem(ElementName="GetResult ")]
public List<string> Array = new List<string>();
public List<string> Get()
{
this.Array.Add("Apple");
this.Array.Add("Orange");
this.Array.Add("Pears");
return this.Array;
}
I need the XML response to be like this
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<GetResponse xmlns="http://tempuri.org/">
<GetResult xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<GetResult >Apple</GetResult >
<GetResult >Orange</GetResult >
<GetResult >Pears</GetResult >
</GetResult>
</GetResponse>
But the actual result is
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<GetResponse xmlns="http://tempuri.org/">
<GetResult xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:string>Apple</a:string>
<a:string>Orange</a:string>
<a:string>Pears</a:string>
</GetResult>
</GetResponse>
How to get my desired response. Please someone help me
Try:
[XmlArrayItem(ElementName="")]
public List<string> GetResult = new List<string>();
Happy Code!

Edit soap response C#

i have a visual studio web service and one of the [WebMethod] returns an array object like this:
public createSerial[] Create(string inputSerial)
{
Bus bus = new Bus();
return bus.CreateOperation()
}
when i call it it generates the following response:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<CreateSerial xmlns="http://london.com/v1/">
<CreateSerialRequestResult>
<CreateSerialResponse>
<serial xmlns="urn:microsoft-dynamics-schemas/ve">57</serial>
</CreateSerialResponse>
</CreateSerialRequestResult>
</CreateSerial>
</soap:Body>
</soap:Envelope>
but i want only this :
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<CreateSerial xmlns="http://london.com/v1/">
<serial>57</serial>
</CreateSerial>
</soap:Body>
</soap:Envelope>
How can i do this ?
ParameterStyle = SoapParameterStyle.Bare

Customize XML Serialize With new Tags And Attributes And Root

This is my Type:
public class MyObject {
public string destAdd { get; set; }
public long Time { get; set; }
public int maxNumb { get; set; }
public Account AccountCredentials { get; set; }
public System.String Serialize() {
String result = "";
XmlSerializer xs = new XmlSerializer(typeof(MyObject));
MemoryStream ms = new MemoryStream();
xs.Serialize(ms, this);
result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
ms.Close();
ms.Dispose();
xs = null;
return result;
}
public static MyObject DeSerialize(String s) {
MyObject result = new MyObject();
XmlSerializer xs = new XmlSerializer(typeof(MyObject));
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(s));
result = (MyObject)xs.Deserialize(ms);
ms.Close();
ms.Dispose();
xs = null;
return result;
}
}
Then I serialize it like this:
MyObject obj = new MyObject();
obj.destAdd = "Destination";
obj.maxNumb = 99;
obj.Time = 128;
obj.Account = new Account { username = "user", password = "pass" };
string seializeObj = obj.Serialize();
The result is:
<?xml version="1.0"?>
<MyObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<destAdd>Destination</destAdd>
<Time>128</Time>
<maxNumb>99</maxNumb>
<Account>
<username>user</username>
<password>pass</password>
</Account>
</MyObject>
But I need the following result:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:smag="http://targetaddress.com/">
<soapenv:Header>
<Account>
<username>user</username>
<password>pass</password>
</Account>
</soapenv:Header>
<soapenv:Body>
<smag:myobjinfos>
<destAdd>Destination</destAdd>
<Time>128</Time>
<maxNumb>99</maxNumb>
</smag:myobjinfos>
</soapenv:Body>
</soapenv:Envelope>
How can I implement the serialize to get this result? any suggestion?
It appears that you are trying to call a web service, with a custom security header. Usually, the easiest way to do this would be to generate a set of proxy classes from the WSDL of the target webservice.
Either
Right click on the use Add Service Reference / Add Web Reference from the Visual Studio
Or, if you have the WSDL and xsd files of the service, then use wsdl.exe command line tool (e.g. wsdl.exe *.wsdl *.xsd //language:c#)
See here on how to set security information on the ws:security header
However, if you are 100% sure that you need to obtain the exact soapEnv Xml above, I would suggest you keep your code 'as is' (i.e. just serialize MyObject in its default format using XmlSerializer or DataContractSerializer), and then use a XslCompiledTransform.
This XSLT will do exactly this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="/MyObject">
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:smag="http://targetaddress.com/">
<soapenv:Header>
<Account>
<username><xsl:value-of select="Account/username"/></username>
<password><xsl:value-of select="Account/password"/></password>
</Account>
</soapenv:Header>
<soapenv:Body>
<smag:myobjinfos>
<destAdd><xsl:value-of select="destAdd"/></destAdd>
<Time><xsl:value-of select="Time"/></Time>
<maxNumb><xsl:value-of select="maxNumb"/></maxNumb>
</smag:myobjinfos>
</soapenv:Body>
</soapenv:Envelope> </xsl:template>
</xsl:stylesheet>
Converts
<?xml version="1.0"?>
<MyObject>
<destAdd>Destination</destAdd>
<Time>128</Time>
<maxNumb>99</maxNumb>
<Account>
<username>user</username>
<password>pass</password>
</Account>
</MyObject>
To this:
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:smag="http://targetaddress.com/">
<soapenv:Header>
<Account>
<username>user</username>
<password>pass</password>
</Account>
</soapenv:Header>
<soapenv:Body>
<smag:myobjinfos>
<destAdd>Destination</destAdd>
<Time>128</Time>
<maxNumb>99</maxNumb>
</smag:myobjinfos>
</soapenv:Body>
</soapenv:Envelope>

Categories

Resources