views:

427

answers:

1

I try sing and encrypt SOAP message in ASP.NET Web Service.

//I have Crypt class, which input parameters is Stream:
public class CryptUtility
 {
      public virtual Stream EncryptAndSingXml (Stream inputStream)
      {
         XmlTextReader reader = new XmlTextReader(inputStream);
         XmlDocument doc = new XmlDocument();
         doc.Load(reader);

         // in this place I encrypt and sign SOAP message
         foreach (string xPathQuery in soapElement)
          {
          XmlNodeList nodesToEncrypt = doc.SelectNodes(xPathQuery, nsMan);
            foreach (XmlNode nodeToEncrypt in nodesToEncrypt)
              {
                // method EncryptString crypt only string from XmlNode
                nodeToEncrypt.InnerXml = EncryptString();
              }
           }

         // !!!
         //               I        THINK  HERE IS A PROBLEM 
         //
         //it return plain stream, no encrypt stream
         MemoryStream retStream = new MemoryStream();
         XmlTextWriter writer = new XmlTextWriter(retStream, Encoding.UTF8);
         doc.Save(retStream);
         return retStream;
      }
 }

I used CryptUtility object in Soap extension class:

public class SoapMsg : SoapExtension
 {
     private CryptUtility cryptUtil; //this object crypt and sing SOAP message
     //  ...

     //this method copy stream
     private void CopyStream(Stream from, Stream to)
     {
     TextReader reader = new StreamReader(from);
     TextWriter writer = new StreamWriter(to);
     writer.Write(reader.ReadToEnd());
     writer.Flush();
     }

     //this method sing and encrypt SOAP message, I call this method in stage  AfterSerialize
     private void CryptMessage()
     {
     newStream.Position = 0;
     Stream retStream = cryptUtil.EncryptAndSingXml(newStream);
     retStream.Position = 0;
     CopyStream(retStream, oldStream);
     }

     public override void ProcessMessage(SoapMessage message)
     {
       switch (message.Stage)
         {
           case SoapMessageStage.BeforeSerialize:
              break;
           case SoapMessageStage.AfterSerialize:
           {
           // call the crypt and sing method
           CryptMessage();
           //save the SOAP message, the message is not encrypt
           Log(message, "AfterSerialize");
           }
             break;
           case SoapMessageStage.BeforeDeserialize:
              break;
           case SoapMessageStage.AfterDeserialize:
               break;
            default:
              throw new ArgumentException("error.");
           }

        }
     // ...
 }

Problem is, when I log SOAP message in AfterDeserialize the XML is plain text, but it should be encrypt Can somebody help me, where can be problem , or what can I do bad?

Because first I use method EncryptAndSingXml as void in class SoapMsg, and it work correct!!! Something like this :

 public class SoapMsg : SoapExtension
 {
 //...
      public void EncryptAndSingXml()
      {...}
 //...
     public override void ProcessMessage(SoapMessage message)
     {
       switch (message.Stage)
         {
           //...
           case SoapMessageStage.AfterSerialize:
           EncryptAndSingXml();
               break;
           //...
        }
     // ...
 }

But when I makec class CryptUtility and method EncryptAndSingXml() as virtual it doesn't work. :( Can somebody help me ?

A: 

It doesn't look like you are modifying message at all!

And, please show where you create an instance of CryptUtility.

Also, your code is pretty bad. Try this:

public class CryptUtility
{
    public virtual Stream EncryptAndSingXml(Stream inputStream, IEnumerable<string> soapElement)
    {
        XmlDocument doc = new XmlDocument();
        using (XmlReader reader = XmlReader.Create(inputStream))
        {
            doc.Load(reader);
        }

        // in this place I encrypt and sign SOAP message
        XmlNamespaceManager nsMan = new XmlNamespaceManager(doc.NameTable);
        foreach (string xPathQuery in soapElement)
        {
            XmlNodeList nodesToEncrypt = doc.SelectNodes(xPathQuery, nsMan);
            foreach (XmlNode nodeToEncrypt in nodesToEncrypt)
            {
                // method EncryptString crypt only string from XmlNode
                nodeToEncrypt.InnerXml = EncryptString(nodeToEncrypt.InnerXml);
            }
        }

        // !!!
        //               I        THINK  HERE IS A PROBLEM 
        //
        //it return plain stream, no encrypt stream
        using (MemoryStream retStream = new MemoryStream())
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = Encoding.UTF8;
            using (XmlWriter writer = XmlWriter.Create(retStream, settings))
            {
                doc.WriteTo(writer);
            }
            return retStream;
        }
    }
}

and

public class SoapMsg : SoapExtension
{
    private CryptUtility cryptUtil; //this object crypt and sing SOAP message
    //  ...

    //this method copy stream
    private void CopyStream(Stream from, Stream to)
    {
        using (TextReader reader = new StreamReader(from))
        {
            using (TextWriter writer = new StreamWriter(to))
            {
                writer.Write(reader.ReadToEnd());
                writer.Flush();
            }
        }
    }

    //this method sing and encrypt SOAP message, I call this method in stage  AfterSerialize
    private void CryptMessage()
    {
        newStream.Position = 0;
        using (Stream retStream = cryptUtil.EncryptAndSingXml(newStream))
        {
            retStream.Position = 0;
            CopyStream(retStream, oldStream);
        }
    }

    public override void ProcessMessage(SoapMessage message)
    {
        switch (message.Stage)
        {
            case SoapMessageStage.BeforeSerialize:
                break;
            case SoapMessageStage.AfterSerialize:
                {
                    // call the crypt and sing method
                    CryptMessage();
                    //save the SOAP message, the message is not encrypt
                    Log(message, "AfterSerialize");
                }
                break;
            case SoapMessageStage.BeforeDeserialize:
                break;
            case SoapMessageStage.AfterDeserialize:
                break;
            default:
                throw new ArgumentException("error.");
        }

    }
    // ...
}
John Saunders
I create instace CryptUtility in Initialize. Thank for advanace, it works.What is a reason for use using? for example : using (XmlReader reader = XmlReader.Create(inputStream)) { doc.Load(reader); }I work with ASP.NET only one month.
klerik123456
`using` is used when you create an instance of a type that implements `IDisposable`. It ensures that `IDisposable.Dispose` is called even if an exception is thrown. The rule is - if you create an instance of such a type, you should wrap it in a `using` block.
John Saunders
Thank for advance.From now if my instace implements iterface IDisposable I will create instance with using.
klerik123456