4

I'm trying to get a call to a web service (not sure what the backend is written in) using both a username token (username/pwd) and a client certificate.

Short version: what combination of WCF code/config is needed to generate the SOAP headers below if I have a client cert and a username/password to work with?

Long Version

Below is the service interface as generated by "Add Service Reference" in Visual Studio 2010 (names/URIs changed to protect the innocent):

 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(Namespace="http://servicenamespacehere", ConfigurationName="Service.Contract.ConfigName.Here")]
    public interface IBackendService {

        // CODEGEN: ...
        [System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://servicenamespacehere#Method1")]
        [System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
        void Method1(Method1Params request);

I need the resulting call's SOAP security headers to look as follows:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
   <s:Header>
      <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
         <u:Timestamp u:Id="_0">
            <u:Created>2014-08-26T20:22:50.522Z</u:Created>
            <u:Expires>2014-08-26T20:27:50.522Z</u:Expires>
         </u:Timestamp>
         <o:UsernameToken u:Id="uuid-6f243c9c-fd85-4634-8b57-cb196aee3195-60591">
            <o:Username>myUser</o:Username>
            <o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">somePwd</o:Password>
         </o:UsernameToken>
         <o:BinarySecurityToken u:Id="uuid-6f243c9c-fd85-4634-8b57-cb196aee3195-60592" 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">BASE64TOKENHERE=</o:BinarySecurityToken>
         <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo>
               <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
               <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
               <Reference URI="#_0">
                  <Transforms>
                     <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                  </Transforms>
                  <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                  <DigestValue>BASE64DIGESTHERE=</DigestValue>
               </Reference>
            </SignedInfo>
            <SignatureValue>BASE64SIGNATUREHERE=</SignatureValue>
            <KeyInfo>
               <o:SecurityTokenReference>
                  <o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-6f243c9c-fd85-4634-8b57-cb196aee3195-60592"/>
               </o:SecurityTokenReference>
            </KeyInfo>
         </Signature>
      </o:Security>
   </s:Header>
   SOAP XML PAYLOAD FOLLOWS...

I was not able to find any comnbination of WCF binding/endpoint settings that would support client message credentials that would include both UserName and Certificate types.

As a result of some searches I found someone who indicated that I needed a custom WCF binding to include both credential types, and they pointed to this MSDN link:

http://msdn.microsoft.com/en-us/library/ms751480(v=vs.100).aspx

But when I follow the code example I get an error:

'The service certificate is not provided for target' 

Now the ClientCredentials object has both a ClientCertificate property (which I successfully load via my client cert's thumbprint), but what is the ServiceCertificate for?

What combination of WCF code/config is needed to generate the SOAP headers above if all I have a client cert and a username/password to work with?

Pokechu22
  • 4,984
  • 9
  • 37
  • 62
Mike Marshall
  • 7,788
  • 4
  • 39
  • 63

2 Answers2

5

This can only be done with a code binding:

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

        b.Elements.Add(sec);
        b.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
        b.Elements.Add(new HttpsTransportBindingElement());
Yaron Naveh
  • 23,560
  • 32
  • 103
  • 158
  • 1
    Your answers have helped me solve a vmware wse to wcf migration so much that I wish i could just give you some of my rep directly! Thank you! – Maverik Sep 03 '14 at 16:49
0

I am not sure if i understand it correctly but by looking at your error it looks like you are not passing Certificate while creating end point to authenticate the service.

   // Create the service host
   ServiceHost myServiceHost = 
    new ServiceHost(typeof(Calculator), httpUri);
myServiceHost.AddServiceEndpoint(typeof(ICalculator), binding, "");

// Specify a certificate to authenticate the service.
myServiceHost.Credentials.ServiceCertificate.
    SetCertificate(StoreLocation.LocalMachine,
    StoreName.My,
    X509FindType.FindBySubjectName,
    "Contoso.com");

http://msdn.microsoft.com/en-us/library/ms733098.aspx

dshah1302
  • 48
  • 1
  • 5
  • I just solved this minutes before you posted. Your answer is part of the solution but not all. There are other hoops to jump through if there actually is no service cert ("mutual certs" with only a client cert). I am waiting for the vendor who owns the web service to validate that my calls are working. If so I will come back and consider marking this as the answer. – Mike Marshall Sep 02 '14 at 21:19