views:

465

answers:

2

I'm trying to use WCF to consume a web service provided by a third-party's Oracle Application Server. I pass a username and password in a UsernameToken as part of the request and as part of the response the web service returns a standard security tag in the header which includes a digest and signature.

With my current setup, I successfully send a request to the server and the web service sends the expected response data back. However, when parsing the response WCF throws a MessageSecurityException, with an InnerException.Message of "Supporting token signatures not expected."

My guess is that WCF wants me to configure it to handle the signature and verify it. I have a certificate from the third party that hosts the web service that I should be able to use to verify the signature, although I'm not sure if I'll need it.

Here's a sample header from a response that makes WCF throw the exception:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"&gt;
  <soap:Header>
    <wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"&gt;
      <dsig:Signature xmlns="http://www.w3.org/2000/09/xmldsig#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"&gt;
        <dsig:SignedInfo>
          <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/&gt;
          <dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/&gt;
          <dsig:Reference URI="#_51IUwNWRVvPOcz12pZHLNQ22">
            <dsig:Transforms>
              <dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/&gt;
            </dsig:Transforms>
            <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;
            <dsig:DigestValue>
              [DigestValue here]
            </dsig:DigestValue>
          </dsig:Reference>
          <dsig:Reference URI="#_dI5j0EqxrVsj0e62J6vd6w22">
            <dsig:Transforms>
              <dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/&gt;
            </dsig:Transforms>
            <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;
            <dsig:DigestValue>
              [DigestValue here]
            </dsig:DigestValue>
          </dsig:Reference>
        </dsig:SignedInfo>
        <dsig:SignatureValue>
          [Signature Value Here]
        </dsig:SignatureValue>
        <dsig:KeyInfo>
          <wsse:SecurityTokenReference xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"&gt;
            <wsse:Reference URI="#BST-9nKWbrE4LRv6maqstrGuUQ22" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/&gt;
          </wsse:SecurityTokenReference>
        </dsig:KeyInfo>
      </dsig:Signature>
      <wsse:BinarySecurityToken ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" wsu:Id="BST-9nKWbrE4LRv6maqstrGuUQ22" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"&gt;
        [Security Token Here]
      </wsse:BinarySecurityToken>
      <wsu:Timestamp wsu:Id="_dI5j0EqxrVsj0e62J6vd6w22" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"&gt;
        <wsu:Created>2010-05-26T18:46:30Z</wsu:Created>
      </wsu:Timestamp>
    </wsse:Security>
  </soap:Header>
  <soap:Body wsu:Id="_51IUwNWRVvPOcz12pZHLNQ22" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"&gt;
    [Body content here]
  </soap:Body>
</soap:Envelope>

My binding configuration looks like:

<basicHttpBinding>
  <binding name="myBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
    <security mode="TransportWithMessageCredential">
      <transport clientCredentialType="None" proxyCredentialType="None" realm="" />
      <message clientCredentialType="UserName" algorithmSuite="Default" />
    </security>
  </binding>
</basicHttpBinding>

I think that basically what I have to do is configure WCF to use UserName client credentials in the request and Certificate client credentials in the response. I don't know how to do this though.

I'm new at WCF, so I'm sorry if this is a bit of a dumb question. I've been trying to Google solutions, but there seem to be so many different ways to configure WCF that I'm getting overwhelmed.

Thanks in advance!

A: 

Seems like service isn't waiting for credentials at a place you providing them. Try to specify username and password for transport level instead.

Denis Markelov
The service accepts my credentials in the message with the way I have it set up now. I send the request and WCF receives the correct response. The problem is with WCF failing to deal with the signature in the response.
AlEl
A: 

For anyone who is interested, I was able to work around this problem by creating a CustomMessageEncoder (with help from this MSDN article) to intercept the response message before WCF was able to handle it. There, I removed the BinarySecurityToken and Signature elements from the response before handing it off to WCF. I used the following method to remove the offending elements from the stream:

    private Stream RemoveSignatures(Stream stream)
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(stream);

        XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
        nsMgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
        nsMgr.AddNamespace("dsig", "http://www.w3.org/2000/09/xmldsig#");
        nsMgr.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

        XmlNode signatureNode = doc.SelectSingleNode("/soap:Envelope/soap:Header/wsse:Security/dsig:Signature", nsMgr);
        XmlNode binarySecurityTokenNode = doc.SelectSingleNode("/soap:Envelope/soap:Header/wsse:Security/wsse:BinarySecurityToken", nsMgr);
        XmlNode headerNode = doc.SelectSingleNode("/soap:Envelope/soap:Header/wsse:Security", nsMgr);

        headerNode.RemoveChild(signatureNode);
        headerNode.RemoveChild(binarySecurityTokenNode);

        return new MemoryStream(new UTF8Encoding().GetBytes(doc.OuterXml));
    }

Obviously this is not the greatest solution. It's very 'hacky'. But it works and if need be I can continue using it because the message security is already being taken care of by HTTPS transport.

If anyone can tell me a better way to solve this, I'm open.

AlEl