L
lissbpp
I’ve got a problem with a custom SoapExtension that uses encryption. I am
encrypting the <soap:Body> element using this library:
http://www.obviex.com/samples/EncryptionWithSalt.aspx. The error that I am
getting is intermittent for users (if a user tries the service again many
times it will work). The webservice gets around 50K requests per day and I
get around 100-200 of these errors, which is a fairly low occurrence but it’s
driving me nuts trying to figure out the problem.
This is a smart client application that shares an assembly both on the agent
and server that deals with the SoapExtension. The SoapExtension is
configured in app.config and web.config respectively.
My problem:
For some reason I am getting SoapMessages that do not have a closing
</soap:Body> & </soap:Envelope> on both the client and server. Exception
reads: “Unexpected end of file has occurred. The following elements are not
closed: soap:Body, soap:Envelope.â€
Example soap message:
<?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:Header><EncryptionHeader
xmlns="http://mystuff.com " /></soap:Header><soap:Body>Gv/RcjUTg8ctp…[END]
The SoapExtension:
using System;
using System.Text;
using System.Web.Services.Protocols;
using System.IO;
using System.Web.Services;
using System.Net;
using System.Xml;
using System.Text.RegularExpressions;
namespace MyStuff
{
public class SoapExtension : SoapExtension
{
Stream _wireStream;
Stream _applicationStream;
public override Stream ChainStream(Stream stream)
{
_wireStream = stream;
_applicationStream = new MemoryStream();
return _applicationStream;
}
public override object GetInitializer(LogicalMethodInfo methodInfo,
SoapExtensionAttribute attribute)
{
return null;
}
public override object GetInitializer(Type WebServiceType)
{
return null;
}
public override void Initialize(object initializer)
{
return;
}
void Copy(Stream from, Stream to)
{
TextReader reader = new StreamReader(from);
TextWriter writer = new StreamWriter(to);
writer.WriteLine(reader.ReadToEnd());
writer.Flush();
}
private void WriteInput()
{
string soapMessage = string.Empty;
try
{
XmlDocument soapXML = new XmlDocument();
string passPhrase = "XXX"; // can be any string
string initVector = "XXX†// must be 16 bytes
// Before encrypting data, we will append plain text to a
random
// salt value, which will be between 4 and 8 bytes long
(implicitly
// used defaults).
Crypto crypto = new Crypto(passPhrase, initVector);
TextReader streamReader = new StreamReader(_wireStream);
TextWriter streamWriter = new
StreamWriter(_applicationStream);
soapMessage = streamReader.ReadToEnd();
soapXML.LoadXml(soapMessage);
XmlNamespaceManager xmlnsSoap = new
XmlNamespaceManager(soapXML.NameTable);
xmlnsSoap.AddNamespace("soap",
"http://schemas.xmlsoap.org/soap/envelope/");
//NOTE: If we have an encryption header lets decrypt the
packet <soap:Body> only
XmlNode soapHeader =
soapXML.SelectSingleNode("soap:Envelope/soap:Header", xmlnsSoap);
if (soapHeader != null)
{
if (soapHeader["EncryptionHeader"] != null)
{
XmlNode bodyNode =
soapXML.SelectSingleNode("soap:Envelope/soap:Body", xmlnsSoap);
bodyNode.InnerXml = crypto.Decrypt(bodyNode.InnerXml);
}
}
streamWriter.Write(soapXML.OuterXml);
streamWriter.Flush();
Copy(_wireStream, _applicationStream);
//NOTE: Rewind stream to the begining
_applicationStream.Position = 0;
}
catch (Exception ex)
{
ex.Data.Add("SoapMessage", soapMessage);
ExceptionProvider.HandleException(ex, "Client");
}
}
private void WriteOutput()
{
string soapMessage = string.Empty;
try
{
_applicationStream.Position = 0;
XmlDocument soapXML = new XmlDocument();
string passPhrase = "XXX"; // can be any string
string initVector = "XXX"; // must be 16 bytes
// Before encrypting data, we will append plain text to a
random
// salt value, which will be between 4 and 8 bytes long
(implicitly
// used defaults).
Crypto crypto = new Crypto(passPhrase, initVector);
TextReader streamReader = new
StreamReader(_applicationStream);
TextWriter streamWriter = new StreamWriter(_wireStream);
soapMessage = streamReader.ReadToEnd();
soapXML.LoadXml(soapMessage);
XmlNamespaceManager xmlnsSoap = new
XmlNamespaceManager(soapXML.NameTable);
xmlnsSoap.AddNamespace("soap",
"http://schemas.xmlsoap.org/soap/envelope/");
//NOTE: If we have an encryption header lets encrypt the
packet <soap:Body> only
XmlNode soapHeader =
soapXML.SelectSingleNode("soap:Envelope/soap:Header", xmlnsSoap);
if (soapHeader != null)
{
if (soapHeader["EncryptionHeader"] != null)
{
bodyNode.InnerText =
crypto.Encrypt(bodyNode.InnerXml);
}
}
streamWriter.Write(soapXML.OuterXml);
streamWriter.Flush();
//NOTE: Rewind stream to the begining
Copy(_applicationStream, _wireStream);
}
catch (Exception ex)
{
ex.Data.Add("SoapMessage", soapMessage);
ExceptionProvider.HandleException(ex, "Client");
}
}
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeDeserialize:
WriteInput();
break;
case SoapMessageStage.AfterDeserialize:
break;
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
WriteOutput();
break;
default:
throw new Exception("invalid stage");
}
}
}
}
Any help would be greatly appreciated.
encrypting the <soap:Body> element using this library:
http://www.obviex.com/samples/EncryptionWithSalt.aspx. The error that I am
getting is intermittent for users (if a user tries the service again many
times it will work). The webservice gets around 50K requests per day and I
get around 100-200 of these errors, which is a fairly low occurrence but it’s
driving me nuts trying to figure out the problem.
This is a smart client application that shares an assembly both on the agent
and server that deals with the SoapExtension. The SoapExtension is
configured in app.config and web.config respectively.
My problem:
For some reason I am getting SoapMessages that do not have a closing
</soap:Body> & </soap:Envelope> on both the client and server. Exception
reads: “Unexpected end of file has occurred. The following elements are not
closed: soap:Body, soap:Envelope.â€
Example soap message:
<?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:Header><EncryptionHeader
xmlns="http://mystuff.com " /></soap:Header><soap:Body>Gv/RcjUTg8ctp…[END]
The SoapExtension:
using System;
using System.Text;
using System.Web.Services.Protocols;
using System.IO;
using System.Web.Services;
using System.Net;
using System.Xml;
using System.Text.RegularExpressions;
namespace MyStuff
{
public class SoapExtension : SoapExtension
{
Stream _wireStream;
Stream _applicationStream;
public override Stream ChainStream(Stream stream)
{
_wireStream = stream;
_applicationStream = new MemoryStream();
return _applicationStream;
}
public override object GetInitializer(LogicalMethodInfo methodInfo,
SoapExtensionAttribute attribute)
{
return null;
}
public override object GetInitializer(Type WebServiceType)
{
return null;
}
public override void Initialize(object initializer)
{
return;
}
void Copy(Stream from, Stream to)
{
TextReader reader = new StreamReader(from);
TextWriter writer = new StreamWriter(to);
writer.WriteLine(reader.ReadToEnd());
writer.Flush();
}
private void WriteInput()
{
string soapMessage = string.Empty;
try
{
XmlDocument soapXML = new XmlDocument();
string passPhrase = "XXX"; // can be any string
string initVector = "XXX†// must be 16 bytes
// Before encrypting data, we will append plain text to a
random
// salt value, which will be between 4 and 8 bytes long
(implicitly
// used defaults).
Crypto crypto = new Crypto(passPhrase, initVector);
TextReader streamReader = new StreamReader(_wireStream);
TextWriter streamWriter = new
StreamWriter(_applicationStream);
soapMessage = streamReader.ReadToEnd();
soapXML.LoadXml(soapMessage);
XmlNamespaceManager xmlnsSoap = new
XmlNamespaceManager(soapXML.NameTable);
xmlnsSoap.AddNamespace("soap",
"http://schemas.xmlsoap.org/soap/envelope/");
//NOTE: If we have an encryption header lets decrypt the
packet <soap:Body> only
XmlNode soapHeader =
soapXML.SelectSingleNode("soap:Envelope/soap:Header", xmlnsSoap);
if (soapHeader != null)
{
if (soapHeader["EncryptionHeader"] != null)
{
XmlNode bodyNode =
soapXML.SelectSingleNode("soap:Envelope/soap:Body", xmlnsSoap);
bodyNode.InnerXml = crypto.Decrypt(bodyNode.InnerXml);
}
}
streamWriter.Write(soapXML.OuterXml);
streamWriter.Flush();
Copy(_wireStream, _applicationStream);
//NOTE: Rewind stream to the begining
_applicationStream.Position = 0;
}
catch (Exception ex)
{
ex.Data.Add("SoapMessage", soapMessage);
ExceptionProvider.HandleException(ex, "Client");
}
}
private void WriteOutput()
{
string soapMessage = string.Empty;
try
{
_applicationStream.Position = 0;
XmlDocument soapXML = new XmlDocument();
string passPhrase = "XXX"; // can be any string
string initVector = "XXX"; // must be 16 bytes
// Before encrypting data, we will append plain text to a
random
// salt value, which will be between 4 and 8 bytes long
(implicitly
// used defaults).
Crypto crypto = new Crypto(passPhrase, initVector);
TextReader streamReader = new
StreamReader(_applicationStream);
TextWriter streamWriter = new StreamWriter(_wireStream);
soapMessage = streamReader.ReadToEnd();
soapXML.LoadXml(soapMessage);
XmlNamespaceManager xmlnsSoap = new
XmlNamespaceManager(soapXML.NameTable);
xmlnsSoap.AddNamespace("soap",
"http://schemas.xmlsoap.org/soap/envelope/");
//NOTE: If we have an encryption header lets encrypt the
packet <soap:Body> only
XmlNode soapHeader =
soapXML.SelectSingleNode("soap:Envelope/soap:Header", xmlnsSoap);
if (soapHeader != null)
{
if (soapHeader["EncryptionHeader"] != null)
{
bodyNode.InnerText =
crypto.Encrypt(bodyNode.InnerXml);
}
}
streamWriter.Write(soapXML.OuterXml);
streamWriter.Flush();
//NOTE: Rewind stream to the begining
Copy(_applicationStream, _wireStream);
}
catch (Exception ex)
{
ex.Data.Add("SoapMessage", soapMessage);
ExceptionProvider.HandleException(ex, "Client");
}
}
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeDeserialize:
WriteInput();
break;
case SoapMessageStage.AfterDeserialize:
break;
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
WriteOutput();
break;
default:
throw new Exception("invalid stage");
}
}
}
}
Any help would be greatly appreciated.