tags:

views:

238

answers:

2

I call method in Soap extension which decrypt and verify sing Soap message. I have this classes:

I have class, which decrypt and verify sign Soap message, which return stream back in Soap extension class :

Method DecryptAndVerifySingXml and GetGuid use stream from class soap extension.

public class CryptUtility
{
    public virtual Stream DecryptAndVerifySingXml(Stream inputStream)
    {
        XmlDocument doc = new XmlDocument();

        using (XmlTextReader reader = new XmlTextReader(inputStream))
        {
            doc.Load(reader);
        }


        using (MemoryStream retStream = new MemoryStream())
        {
            retStream.Position = 0;
            doc.Save(retStream);
        }

        //.....crypt and verify sing

        if (signedXml.CheckSignature(Key) == false)
        {
            throw new SecurityException("error");
        }

        else
        {
            using (MemoryStream retStream = new MemoryStream())
            {
                doc.Save(retStream);
                return retStream;
            }
        }
    }

    //get value from Soap header
    public string GetGuid(MemoryStream inputStream)
    {
        inputStream.Position = 0;

        string soapBodyString = Encoding.UTF8.GetString(inputStream.ToArray());

        XmlDocument doc = new XmlDocument();
        doc.LoadXml(soapBodyString);

        if (doc.GetElementsByTagName("Ticket").Item(0).InnerText == "")
        {
            throw new SecurityException("Neplatny uzivatel");
        }
        else
        {
            return doc.GetElementsByTagName("Ticket").Item(0).InnerText;
        }

    }
}

I use class CryptUtility in Soap extension class:

public class SoapMsg : SoapExtension
    {

        private CryptUtility cryptUtil = null;
        string GUID;

        //...
        public override void Initialize(object initializer)
        {
            SoapMsgAttribute attribute =
              initializer as SoapMsgAttribute;
            soapElement = attribute.SoapElementArray;

            //create instance
            cryptUtil = new CryptUtility();
        }

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

        private void DecryptMessage()
        {
            using (MemoryStream copyOldStream = new MemoryStream())
            {
                CopyStream(oldStream, copyOldStream);

                copyOldStream.Position = 0;
                using (Stream retStream = cryptUtil.DecryptAndVerifySingXml(copyOldStream)
                {
                    retStream.Position = 0; //  < == in this place is bug   !!! line 183.
                    newStream.Position = 0;
                    CopyStream(retStream, newStream);
                    newStream.Position = 0;
                }
            }
        }


         public override void ProcessMessage(SoapMessage message)
        {
            switch (message.Stage)
            {
                case SoapMessageStage.BeforeSerialize:
                    break;
                case SoapMessageStage.AfterSerialize:
                    {
                    }
                    break;
                case SoapMessageStage.BeforeDeserialize:
                    {
                        using (MemoryStream tempStream = new MemoryStream())
                        {
                            CopyStream(oldStream, tempStream);

                            tempStream.Position = 0;

                            GUID = cryptUtil.GetGuid(tempStream);

                            oldStream.Position = 0;

                            // call method, in which is bug
                            DecryptMessage();
                    }
                    break;
                case SoapMessageStage.AfterDeserialize:
                    break;
                default:
                    throw new ArgumentException("error");
            }
        }


    }
 }

In ProcessMessage in BeforeDeserialize I call method DecryptMessage() in wich is bug. On client side Sopa extension finish with this error :

System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.ObjectDisposedException: Cannot access a closed Stream. at System.IO.__Error.StreamIsClosed()

The error is in line : retStream.Position = 0; // < == in this place is bug !!! line 183. in method DecryptMessage().

First I used google, but I don't find solution for this error. Can somebody help me ?

+2  A: 

The problem is that you're disposing of the stream which you then return - so the caller won't be able to use it.

Get rid of the using statements for the streams you return. You're also not using the stream in the first block, and you can get rid of the "else". Here's the complete DecryptVerifySignXml method with these changes:

public virtual Stream DecryptAndVerifySignXml(Stream inputStream)
{
    XmlDocument doc = new XmlDocument();

    using (XmlTextReader reader = new XmlTextReader(inputStream))
    {
        doc.Load(reader);
    }

    //.....crypt and verify sing

    if (!signedXml.CheckSignature(Key))
    {
        throw new SecurityException("error");
    }

    MemoryStream retStream = new MemoryStream();
    doc.Save(retStream);
    retStream.Position = 0; // Rewind so it's ready to use
    return retStream;
}

(I'm not sure the name of the method is particularly valid, I have to say - that method isn't doing any decryption and it's not signing anything - it's just loading some XML and checking an existing signature. Anyway, that's by the by...)

Your CopyStream method is broken, however - it assumes the contents is UTF-8-encoded text. That may be true in some cases, but not all. You should use something like this instead:

static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[8192];
    int bytesRead;
    while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, bytesRead);
    }
}
Jon Skeet
Thank for your advance, it was helpfull.
klerik123456
+2  A: 

Remove using from your retStream declaration; so change this

using (MemoryStream retStream = new MemoryStream())

with this

MemoryStream retStream = new MemoryStream();
Rubens Farias
Right, once using-block is left (either through fall-through or jumping/crashing out of it), the object will be destroyed (and the Stream closed) asap. So if you want to keep it outside the block, do not use "using"!
Marcel J.
@Marcel, ty; I already had a lot problems returning "used variables", so now I understand I must take care returning them; btw, why .net dispose them, as still a reference to them? I'll open a question about this
Rubens Farias