Configuring the "UsernameForCertificate" authentication mode

I want to write a WCF client that authenticates itself to a WCF service using the "UsernameForCertificate" authentication mode (a very simple scenario!). However, I'm having trouble finding the right configuration settings to use for the client and the service. I'm using the September CTP release.

I defined the client binding as follows:

<wsHttpBinding>
    <binding configurationName="myBinding">
            <security mode="Message">
                  <message  clientCredentialType="UserName"  />
             </security>
    </binding>
</wsHttpBinding>

<client>
   <endpoint configurationName="myClient"
      address="
http://mymachine/stockService/endpoint1"
      contract="Stocks.IStock"
      binding="wsHttpBinding"
      bindingConfiguration="myBinding">
        <identity>
             <certificate encodedValue="..."/>
        </identity>
   </endpoint>
</client>


But I get the following exception:

InvalidOperationException

ClientCredentials is unable to create a remote token provider for token parameters System.ServiceModel.Security.Tokens.X509SecurityTokenParameters:
InclusionMode: Never
ReferenceStyle: Internal
RequireDerivedKeys: True

The service uses the same binding (anyway the error occurs before anything is sent to the server, so the server's binding doesn't matter as far as this error goes).

I also explored other configuration settings for the <security> element such as

     <security authenticationMode="UserNameForCertificate" />

But none worked. Can someone who got this authentication mode working provide me with the right configuration settings to enable it

Many Thanks,
Youcef




Answer this question

Configuring the "UsernameForCertificate" authentication mode

  • Federico Silberberg

    Youcef,

    I believe the client username credentials can only be used if you set the security mode="transport", which means that the client credentials is sent on the wire only over HTTPS. This is for best security purposes as unsigned tokens (such as the username token) are best used for authentication only coupled with transport security.

    Therefore, configurations look as such:

         <security mode="TransportWithMessageCredential">
          <!-- Windows credentials by default -->
          <message clientCredentialType ="UserName"/>
         </security>

          OR

         <security mode="Message">
          <message clientCredentialType="Certificate" />
         </security>

    Stay tuned to my blog as I am in the midst of setting up some samples on how to further extend the security settings. Also, do take note of some caveats and bugs that are present in the Sept-CTP drop. I have blogged about some issues here.

    http://www.softwaremaker.net/blog/BugInTheBasicHttpBindingWSSecurityOfTheWCFSeptCTPDrop.aspx

    Hope this helps.



  • eric_1234

    You need to specify on the client where to find the server certificate to sign and encrypt the message with for this authentication mode. This can either be done in code like this (this is an example only)

                // WSSecurityUsernameServiceSoapProxy proxy = new WSSecurityUsernameServiceSoapProxy("WSSecurityUsernameServiceSoap");
                WSSecurityUsernameServiceSoapProxy proxy = new
                        WSSecurityUsernameServiceSoapProxy(
                            binding,
                            new EndpointAddress(
                            new Uri("http://mfussell-base/WSSecurityUsernamePolicy/WSSecurityUsernameService.asmx"),
                            Identity.CreateDnsIdentity("WSE2QuickStartServer")));
               
          //Set the client and server credentials
                string username = "mfussell";
                //username
                proxy.ClientCredentials.UserNamePassword.UserName = username;
                byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(username);
                Array.Reverse(passwordBytes);
                string passwordEquivalent = Convert.ToBase64String(passwordBytes);
                //password
                proxy.ClientCredentials.UserNamePassword.Password = passwordEquivalent;
                //server certificate
                proxy.ChannelFactory.Credentials.ServiceCertificate.
                      SetX509CertificateBySubjectDistinguishedName("cn=WSE2QuickStartServer", StoreLocation.CurrentUser, StoreName.AddressBook);

    Or you can set this as a behavior in config like this (example only)

     <system.serviceModel>
      <client>
       <endpoint
        address="http://mfussell-base/WSSecurityUsernamePolicy/WSSecurityUsernameService.asmx"      
            binding="wsHttpBinding"
            contract="WSSecurityUsernameServiceSoap"
            name="WSSecurityUsernameServiceSoap"
            bindingConfiguration="UsernameOverCertificate">
        <!--Server certificate set in code but can also be set in behaviorConfiguration="SpecifyingServiceCredentialForNoNego"-->
        <identity >
              <!--identity is required if the certificate name is different from the host base addres -->
         <dns value="WSE2QuickStartServer"/>
        </identity>
       </endpoint>
      </client>
       
      <bindings>
       <wsHttpBinding>
        <binding name="UsernameOverCertificate">
         <security mode="Message">
          <message clientCredentialType="UserName"/>
         </security>
        </binding>
       </wsHttpBinding>   
      </bindings>

      <behaviors>
       <behavior name="SpecifyingServiceCredentialForNoNego">
        <clientCredentials>
         <serviceCertificate x509FindType="FindBySubjectDistinguishedName"
                                  findValue="cn=WSE2QuickStartServer" />
        </clientCredentials>
       </behavior>
      </behaviors>

       </system.serviceModel>

    Thanks.

    Mark Fussell
    WCF Security Team



  • Configuring the "UsernameForCertificate" authentication mode