4

In my previous question I've tried to connect to JAVA service that required custom security.

I've created custom MessageEncoder to add attributes required by service, but after trying to send request, I get this response:

<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
    <soapenv:Header xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
        <wsa:MessageID>urn:uuid:ab595a3b-cb2f-450c-a65a-c260c40f9802</wsa:MessageID>
        <wsa:Action>urn:queryQueryDzException</wsa:Action>
        <wsa:RelatesTo>urn:uuid:599290c3-1034-46e7-90a6-a3172e855c6d</wsa:RelatesTo>
    </soapenv:Header>
    <soapenv:Body>
        <soapenv:Fault>
            <soapenv:Code>
                <soapenv:Value>soapenv:Receiver</soapenv:Value>
            </soapenv:Code>
            <soapenv:Reason>
                <soapenv:Text xml:lang="en-US">WSDoAllReceiver: security processing failed</soapenv:Text>
            </soapenv:Reason>
            <soapenv:Detail>
                <Exception>org.apache.axis2.AxisFault: WSDoAllReceiver: security processing failed
    at org.apache.rampart.handler.WSDoAllReceiver.processBasic(WSDoAllReceiver.java:216)
    at org.apache.rampart.handler.WSDoAllReceiver.processMessage(WSDoAllReceiver.java:85)
    at org.apache.rampart.handler.WSDoAllHandler.invoke(WSDoAllHandler.java:72)
    at org.apache.axis2.engine.Phase.invokeHandler(Phase.java:340)
    at org.apache.axis2.engine.Phase.invoke(Phase.java:313)
    at org.apache.axis2.engine.AxisEngine.invoke(AxisEngine.java:262)
    at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:168)
    at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:172)
    at org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:146)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.ha.tcp.ReplicationValve.invoke(ReplicationValve.java:318)
    at org.apache.catalina.ha.session.JvmRouteBinderValve.invoke(JvmRouteBinderValve.java:192)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1502)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1458)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.ws.security.WSSecurityException: The signature or decryption was invalid
    at org.apache.ws.security.processor.SignatureProcessor.verifyXMLSignature(SignatureProcessor.java:393)
    at org.apache.ws.security.processor.SignatureProcessor.handleToken(SignatureProcessor.java:188)
    at org.apache.ws.security.WSSecurityEngine.processSecurityHeader(WSSecurityEngine.java:396)
    at org.apache.ws.security.WSSecurityEngine.processSecurityHeader(WSSecurityEngine.java:304)
    at org.apache.ws.security.WSSecurityEngine.processSecurityHeader(WSSecurityEngine.java:249)
    at org.apache.rampart.handler.WSDoAllReceiver.processBasic(WSDoAllReceiver.java:213)
    ... 33 more
                </Exception>
            </soapenv:Detail>
        </soapenv:Fault>
    </soapenv:Body>
</soapenv:Envelope>

I'm almost sure my message is correct (I have SoapUI request that is returning correct response and I compared both requests. Problem is that inside SoapUI I've noticed that BinarySecurityToken is send with ValueType=X509PKIPathv1. Unfortunately in .NET this is not supported and I'm using X509v3)

Here is my custom MessageEncoder:

public class CustomTextMessageEncoder : MessageEncoder
{
    private CustomTextMessageEncoderFactory factory;
    private XmlWriterSettings writerSettings;
    private string contentType;

    public CustomTextMessageEncoder(CustomTextMessageEncoderFactory factory)
    {
        this.factory = factory;

        writerSettings = new XmlWriterSettings();
        writerSettings.Encoding = Encoding.GetEncoding(factory.CharSet);
        //writerSettings.ConformanceLevel = ConformanceLevel.Fragment;
        //writerSettings.OmitXmlDeclaration = false;
        contentType = string.Format("{0}; charset={1}", this.factory.MediaType, writerSettings.Encoding.HeaderName);
    }

    public override string ContentType
    {
        get
        {
            return contentType;
        }
    }

    public override string MediaType
    {
        get
        {
            return factory.MediaType;
        }
    }

    public override MessageVersion MessageVersion
    {
        get
        {
            return factory.MessageVersion;
        }
    }

    public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
    {
        byte[] msgContents = new byte[buffer.Count];
        Array.Copy(buffer.Array, buffer.Offset, msgContents, 0, msgContents.Length);
        bufferManager.ReturnBuffer(buffer.Array);

        MemoryStream stream = new MemoryStream(msgContents);

        string incoming = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count);
        Console.WriteLine("Incoming message:");
        Console.WriteLine(incoming);
        Console.WriteLine();

        return ReadMessage(stream, int.MaxValue);
    }

    public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
    {
        XmlReader reader = XmlReader.Create(stream);
        var message = Message.CreateMessage(reader, maxSizeOfHeaders, MessageVersion);

        //Debug.WriteLine("RESPONSE:");
        //Debug.WriteLine(message.ToString());
        return message;
    }

    public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
    {
        Debug.WriteLine("MESSAGE:");
        Debug.WriteLine(message.ToString());
        MemoryStream ms = new MemoryStream();
        XmlDictionaryWriter w = XmlDictionaryWriter.CreateBinaryWriter(ms);
        message.WriteMessage(w);
        w.Flush();
        ms.Position = 0;
        XmlDictionaryReader r = XmlDictionaryReader.CreateBinaryReader(ms, XmlDictionaryReaderQuotas.Max);
        XmlDocument doc = new XmlDocument();
        doc.PreserveWhitespace = true;
        doc.Load(r);

        XmlNode binarySecurityToken = doc.GetElementsByTagName("o:BinarySecurityToken")[0];
        if (binarySecurityToken != null)
        {
            XmlAttribute attr = doc.CreateAttribute("EncodingType");
            attr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary";
            if (binarySecurityToken.Attributes != null) binarySecurityToken.Attributes.Append(attr);
        }

        XmlNode SecurityTokenReference = doc.GetElementsByTagName("o:SecurityTokenReference")[0];
        if (SecurityTokenReference != null)
        {
            XmlAttribute attr = doc.CreateAttribute("wsse11", "TokenType", "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd");
            attr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
            if (SecurityTokenReference.Attributes != null) SecurityTokenReference.Attributes.Append(attr);
        }

        XmlNode wsseReference = doc.GetElementsByTagName("o:Reference")[0];
        if (wsseReference != null)
        {
            XmlAttribute attr = doc.CreateAttribute("ValueType");
            attr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
            if (wsseReference.Attributes != null) wsseReference.Attributes.Append(attr);
        }

        ms = new MemoryStream();
        w = XmlDictionaryWriter.CreateBinaryWriter(ms);
        doc.WriteTo(w);
        w.Flush();
        ms.Position = 0;
        r = XmlDictionaryReader.CreateBinaryReader(ms, XmlDictionaryReaderQuotas.Max);
        Message newMessage = Message.CreateMessage(r, maxMessageSize, message.Version);
        newMessage.Properties.CopyProperties(message.Properties);

        Debug.WriteLine("NEW MESSAGE:");
        Debug.WriteLine(newMessage.ToString());



        ArraySegment<byte> messageBuffer;

        int messageLength;
        using (MemoryStream stream = new MemoryStream())
        {
            using (XmlWriter writer = XmlWriter.Create(stream, writerSettings))
            {
                newMessage.WriteMessage(writer);
            }

            var writeBuffer = stream.ToArray();
            messageBuffer = new ArraySegment<byte>(writeBuffer);

            messageLength = (int)stream.Position;
        }

        int totalLength = messageLength + messageOffset;
        byte[] totalBytes = bufferManager.TakeBuffer(totalLength);
        Array.Copy(messageBuffer.Array, 0, totalBytes, messageOffset, messageLength);

        ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength);
        return byteArray;
    }


    public override void WriteMessage(Message message, Stream stream)
    {
        XmlWriter writer = XmlWriter.Create(stream, writerSettings);
        message.WriteMessage(writer);
        writer.Close();
    }

    public override bool IsContentTypeSupported(string contentType)
    {
        if (base.IsContentTypeSupported(contentType))
        {
            return true;
        }
        if (contentType.Length == MediaType.Length)
        {
            return contentType.Equals(MediaType, StringComparison.OrdinalIgnoreCase);
        }
        else
        {
            if (contentType.StartsWith(MediaType, StringComparison.OrdinalIgnoreCase)
                && (contentType[MediaType.Length] == ';'))
            {
                return true;
            }
        }
        return false;
    }
}

My question is how should I change WriteMessage to correctly add attributes without changing message format (white spaces, new lines). I need this because I'm signing request body using certificate, and my current version is somehow altering message so signature is invalid.

My client creation code:

var binding = new CustomBinding();

var sec = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10);
sec.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters());
sec.MessageSecurityVersion =
    MessageSecurityVersion.
        WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
sec.IncludeTimestamp = false;
sec.MessageProtectionOrder = MessageProtectionOrder.EncryptBeforeSign;

binding.Elements.Add(sec);
binding.Elements.Add(new CustomTextMessageBindingElement("UTF-8", "application/soap+xml", MessageVersion.Soap12WSAddressing10));
b.Elements.Add(new HttpsTransportBindingElement());

var client = new QueryDzPortTypeClient(binding, new EndpointAddress(new Uri("https://dz.query.pl/services/QueryDz"), new DnsEndpointIdentity("My service "), new AddressHeaderCollection()));


client.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>();
client.ChannelFactory.Endpoint.Behaviors.Add(new UsernameTokenProfile11Credentials());


client.ClientCredentials.UserName.UserName = _userName;
client.ClientCredentials.UserName.Password = _password;

client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
    X509CertificateValidationMode.None;
client.ClientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2(@"C:\Program Files\Microsoft WSE\v2.0\Samples\Sample Test Certificates\Server Public.cer");

client.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(@"C:\Program Files\Microsoft WSE\v2.0\Samples\Sample Test Certificates\Client Private.pfx", "wse2qs");

client.Endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;

I've posted my message encoder code: here

Community
  • 1
  • 1
Misiu
  • 4,738
  • 21
  • 94
  • 198

0 Answers0