Answered Consume WCF Service from 3rd Party Client

  • Wednesday, April 11, 2012 9:09 AM
     
      Has Code

    I have written a WCF service using a basicHttpBinding that must be consumed by a third party. Here is my configuration:

          <basicHttpBinding>
    	<binding name="AccountManagementServiceConf" maxReceivedMessageSize="65536">
              <security mode="TransportWithMessageCredential">
                <message clientCredentialType="UserName"/>
              </security>
              <readerQuotas maxArrayLength="65536" maxBytesPerRead="65536" maxStringContentLength="65536"/>
            </binding>
          </basicHttpBinding>     
    


        <services>
          <service name="AccountManagementService.AccountManagementService" behaviorConfiguration="AuthenticationBehaviour">
            <endpoint address="/safe" binding="basicHttpBinding" bindingConfiguration="AccountManagementServiceConf" contract="AccountManagementService.IAccountManagementService">
              <identity>
                <dns value="localhost"/>
              </identity>
            </endpoint>
            <endpoint address="mex" binding="mexHttpsBinding" contract="AccountManagementService.IAccountManagementService" />
          </service>
        </services>
          <serviceBehaviors>
            <behavior name="AuthenticationBehaviour">
              <!-- Username and Password validator-->
              <serviceCredentials>
                <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="AccountManagementService.Authentication.AuthenticationValidator, AccountManagementService"/>
              </serviceCredentials>
              <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
              <serviceMetadata httpsGetEnabled="true"/>
              <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
              <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
          </serviceBehaviors>

    Since this service is being consumed by someone outwith my network I require to have them send a Username/Password along with the message to provide some level of security. I have opted for security mode TransportWithMessageCredential.

    All is well and good when I consume this service from a .NET client, however, when I try to build up a SOAP message to use the service I run into some issues. The following represents the message I am sending to the service:

    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
      <s:Header>
        <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IAccountManagementService/CustomerLookup</Action>
      </s:Header>
      <s:Body>
        <CustomerLookup xmlns="http://tempuri.org/">
          <debtId>30444059</debtId>
        </CustomerLookup>
      </s:Body>
    </s:Envelope>

    I suppose my question is this:

    How do I add in the necessary security information to the headers? I have tried the following but it results in a HTTP 400 Bad Request error:

        <wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/07/secext" soap:mustUnderstand="1">
          <wsse:UsernameToken>
            <wsse:Username>Username</wsse:Username>
            <wsse:Password type="wsse:passwordText">Password</wsse:Password>
          </wsse:UsernameToken>
        </wsse:Security>

    Any ideas or guidance will be welcomed.

All Replies

  • Wednesday, April 11, 2012 10:18 PM
     
     

    the short answer is that you use some web services framework on the client side (non .net as you said) so it must have its api to add message level username. Also note:

    - no need to send that action header, it may actually cause the error

    - turn on WCF trace on the server to get detailed error:

    http://blogs.msdn.com/b/madhuponduru/archive/2006/05/18/601458.aspx

    - turn on wcf logging on the server (or use Fiddler on your working .net client machine) to see how a working message looks like on the wire. Then compare your client message to this one. Note wcf logs will show you that extra action header but it is not really sent, Fiddler is more accurate here.


    http://webservices20.blogspot.com/
    WCF Security, Interoperability And Performance Blog

  • Thursday, April 12, 2012 12:16 PM
     
      Has Code

    Hi Yaron, thanks for the reply.

    I turned on tracing and had a look at the trace file using Microsoft Service Trace Viewer tool.

    I see the following error message:

    Security processor was unable to find a security header in the message. This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties.   This can occur if the service is configured for security and the client is not using security.

    The following warning:

    Description The security protocol cannot verify the incoming message.

    And I can see the following message headers:

    <MessageProperties>
    <Encoder>text/xml; charset=utf-8</Encoder>
    <AllowOutputBatching>False</AllowOutputBatching>
    <Via>https://spwebserver/AccountManagementService/AccountManagementService.svc/safe</Via>
    </MessageProperties>
    <MessageHeaders>
    <wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/07/secext">
    <wsse:UsernameToken>
    <wsse:Username>
    <!-- Removed-->
    </wsse:Username>
    <wsse:Password>
    <!-- Removed-->
    </wsse:Password>
    </wsse:UsernameToken>
    </wsse:Security>
    <To d4p1:mustUnderstand="1" xmlns:d4p1="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">https://spwebserver/AccountManagementService/AccountManagementService.svc/safe</To>
    <Action d4p1:mustUnderstand="1" xmlns:d4p1="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IAccountManagementService/CustomerLookup</Action>
    </MessageHeaders>

    I got the above when firing off a handcrafted message to the service using soapUI.

    I'll trace a proper message from my .NET client and try to inspect the headers within that. I had previously tried to inspect messages with an IClientMessageInspector but that did not show the headers.

    Cheers,

    Liam

  • Friday, April 13, 2012 5:08 AM
    Moderator
     
     

    You need to check the following aspects.

    1.The service is expecting some form of security and the client is set to noe.
    2.The binding between the server and client need to be matched.
    3.It seems that you post the username and password information to the service for authentication, so you need to create and install certificate on the server and client side, and config it in the config file, for more about this, please check this post. http://social.msdn.microsoft.com/forums/en-US/wcf/thread/a7ff98b9-8d63-4c7c-84d6-253e0404ea65/
    4.Sometimes this happens because the message is sending a timestamp to Web Logic Server and the response is coming with no timestamp, for this, please check this article http://blog.latamhub.com/?p=78

    Here is a similar post to which you can refer.
    http://forums.asp.net/t/1567473.aspx/1


    Please mark the replies as answers if they help or unmark if not. If you have any feedback about my replies, please contact msdnmg@microsoft.com Microsoft One Code Framework

  • Tuesday, April 17, 2012 6:53 PM
     
     Answered

    Hi Peter, thanks for your reply.

    I had previously tried looking into all 4 points you had made before seeing your response (and after googling the error message).

    In the end I converted my WCF service into an older style .asmx web service (adding a custom header for security info). Got it all up and running within a couple of hours. The older web services seem so much simpler to communicate with when using 3rd party non .NET clients.

    I'd have liked to have gotten to the bottom of my issue but time just didnt allow for it.

    Anyway, thanks again for taking the time to provide an answer.

    Cheers,

    Liam