.NET Framework Developer Center > .NET Development Forums > Windows Communication Foundation > netTCP - the caller was not authenicated by the service
Ask a questionAsk a question
 

AnswernetTCP - the caller was not authenicated by the service

  • Friday, November 06, 2009 1:15 AMChris Restall Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    I have a functional windows service that hosts a WCF over netTCP.  The service uses message level security with clientCredentialType of certificate:  Host config:

    <system.serviceModel>
    <services>
         <service behaviorConfiguration="chainBehavior" name="MyCompany.Services.AuthenticationService"> 
              <endpoint bindingConfiguration="tcpCertificateSecured" binding="netTcpBinding" contract="MyCompany.ServiceContracts.IAuthenticationService">
                   <identity>
                        <dns value="My Client Cert" />
                   </identity>
              </endpoint>
         </service>
    </services>
    <bindings>
         <netTcpBinding>
              <binding name="tcpCertificateSecured">
                   <security mode="Message">
                        <message clientCredentialType="Certificate" />
                   </security>
              </binding>
         </netTcpBinding>
    </bindings>
    <behaviors>
         <serviceBehaviors>
              <behavior name="chainBehavior">
                   <serviceCredentials>
                        <clientCertificate>
                              <authentication certificateValidationMode="ChainTrust" includeWindowsGroups="False" revocationMode="NoCheck"/>
                        </clientCertificate>
                        <serviceCertificate findValue="My Client Cert" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />
                    </serviceCredentials>
              </behavior>
         </serviceBehaviors>
    </behaviors>
    </system.serviceModel>
    
    


    The client passes the certificate, "My Client Cert", over as specified in the client config:

     <system.serviceModel>
        <bindings>
          <netTcpBinding>
            <binding name="NetTcpBinding_IAuthenticationService" closeTimeout="00:01:00"
                openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
                hostNameComparisonMode="StrongWildcard" listenBacklog="10"
                maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
                maxReceivedMessageSize="65536">
              <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                  maxBytesPerRead="4096" maxNameTableCharCount="16384" />
              <reliableSession ordered="true" inactivityTimeout="00:10:00"
                  enabled="false" />
              <security mode="Message">
                <message clientCredentialType="Certificate" />
              </security>
            </binding>
          </netTcpBinding>
        </bindings>
        <behaviors>
          <endpointBehaviors>
            <behavior name="chainBehavior">
              <clientCredentials>
                <clientCertificate findValue="My Client Cert" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />
                <serviceCertificate>
                  <authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck"/>
                </serviceCertificate>
              </clientCredentials>
            </behavior>
          </endpointBehaviors>
        </behaviors>
        <client>
          <endpoint address="net.tcp://localhost:6968/" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IAuthenticationService"   contract="MyCompany.ServiceContracts.IAuthenticationService" name="IAuthenticationService" 			  behaviorConfiguration="chainBehavior">
            <identity>
              <dns value="My Client Cert" />
            </identity>
          </endpoint>
        </client>
      </system.serviceModel>
    

    The "My Client Cert" is generated from a home spun trusted certificate CA on the service host server and exists in the local machine personal store of the server and deployed to the local machine personal store of all the clients that will be connecting to the service host.  The trusted certificate CA is placed in the Trusted Root Certificate authority on the service host server.  These cannot be moved as the certificates are already deployed in the certificate stores of clients and servers in the field

    When a client connects up to the host service for the first time, it fails with:

    "the caller was not authenicated by the service"

    if I restart the host service, the client connects and authenticates properly.  This is unacceptable though as multiple clients will need to connect to this service and having to restart for each one would be disruptive to those that are already connected.

    If I change the clientCredentialType to "None" it all works on the first go but this is not doing any real certificate security. Any suggestions on how to get ChainTrust to work correctly? 

Answers

  • Friday, November 06, 2009 4:30 AMFrank Xu Lei Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Hi,
    first.
    1.You can change the certificateValidationMode="PeerOrChainTrust".
    if this does not work.
    please make a certificate and set it trusted by Trusted CA and Trusted People. in client  and Server.

    This issues mat help you .
    http://social.msdn.microsoft.com/Forums/en/wcf/thread/6b2d6fca-7a0d-49e4-87ca-65e6b2529d4c


    Frank Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    欢迎访问老徐的中文技术博客:Welcome to My Chinese Technical Blog
    欢迎访问微软WCF中文技术论坛:Welcome to Microsoft Chinese WCF Forum
    欢迎访问微软WCF英文技术论坛:Welcome to Microsoft English WCF Forum
  • Saturday, November 07, 2009 1:54 AMChris Restall Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    Success!  Made a few changes to the config and things are now working with a custom X509CertificateValidator.  Here's the class:
    public class MyCertificateValidator : X509CertificateValidator
        {        
            private const X509RevocationMode ChainTrustRevocationMode = X509RevocationMode.NoCheck;
            private const StoreLocation AuthorityCertStoreLocation = StoreLocation.LocalMachine;
            private const StoreName AuthorityCertStoreName = StoreName.Root;
            private const string AuthorityCertThumbprint = "thethumbprintofmyCAcert";
    
             static MyCertificateValidator()
            {
                X509ChainPolicy policy = new X509ChainPolicy();
                policy.RevocationMode = ChainTrustRevocationMode;
            }
    
            public override void Validate(X509Certificate2 certificate)
            {
                           
                if(certificate==null)
                    throw new SecurityTokenValidationException("No Certificate was passed");
    
                X509Store store = new X509Store(AuthorityCertStoreName, AuthorityCertStoreLocation);
                
                store.Open(OpenFlags.ReadOnly);
                X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, certificate.IssuerName.Name, true);
                if (certs.Count != 1)
                    throw new SecurityTokenValidationException("Cannot find the root authority certificate");
    
                X509Certificate2 rootAuthorityCert = certs[0];
                if (String.Compare(rootAuthorityCert.Thumbprint, AuthorityCertThumbprint, true) != 0)
                    throw new SecurityTokenValidationException("Not signed by our certificate authority");
    
                store.Close();
            }
        }
    
    The service host config is the same as above with a change to the behaviors:
    <serviceBehaviors>
            <behavior name="chainBehavior">
              <serviceDebug includeExceptionDetailInFaults="True" />
              <serviceSecurityAudit messageAuthenticationAuditLevel="SuccessOrFailure" serviceAuthorizationAuditLevel="SuccessOrFailure" auditLogLocation="Application"/>
              <serviceCredentials>
                <clientCertificate>
                  <authentication certificateValidationMode="Custom" customCertificateValidatorType="Security.MyCertificateValidator, Security" trustedStoreLocation="LocalMachine" revocationMode="NoCheck" />
                </clientCertificate>
                <serviceCertificate findValue="My Client Cert" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />
              </serviceCredentials>
            </behavior>
          </serviceBehaviors>
    

    Likewise on the client:

    <endpointBehaviors>        
            <behavior name="chainBehavior">
             <clientCredentials>
                <clientCertificate findValue="My Client Cert" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />
               <serviceCertificate>
                 <authentication certificateValidationMode="Custom" customCertificateValidatorType="Security.MyCertificateValidator, Security" trustedStoreLocation="LocalMachine" revocationMode="NoCheck"/>
               </serviceCertificate> 
             </clientCredentials>
            </behavior>
          </endpointBehaviors>
    
    Hope someone finds this useful as it was hard fought knowledge...

All Replies

  • Friday, November 06, 2009 4:30 AMFrank Xu Lei Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Hi,
    first.
    1.You can change the certificateValidationMode="PeerOrChainTrust".
    if this does not work.
    please make a certificate and set it trusted by Trusted CA and Trusted People. in client  and Server.

    This issues mat help you .
    http://social.msdn.microsoft.com/Forums/en/wcf/thread/6b2d6fca-7a0d-49e4-87ca-65e6b2529d4c


    Frank Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    欢迎访问老徐的中文技术博客:Welcome to My Chinese Technical Blog
    欢迎访问微软WCF中文技术论坛:Welcome to Microsoft Chinese WCF Forum
    欢迎访问微软WCF英文技术论坛:Welcome to Microsoft English WCF Forum
  • Friday, November 06, 2009 8:53 PMChris Restall Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Thanks for looking into this.  In order to use the PeerOrChainTrust, the cert would need to be in trusted people store.  Unfortunately I cannot move the certificates in our already deployed clients and servers.

    This appears to be an issue with System.IdentityModel and the caching it does.  As indicated above, If I recycle the appDomain of the service (restart), clinets can connect.  This issue is covered here:
    http://social.msdn.microsoft.com/forums/en-US/wcf/thread/128c7f27-7626-49ac-8a92-daa45dcda0f1/
    http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/23455b64-6e69-461b-8a5b-08a17467d260

    Its looking like I may need to write a custom validator to get around this.
  • Saturday, November 07, 2009 1:01 AMChris Restall Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    So even wih a customCertificateValidatorType I still have to restart the service everytime a new clinet tries to connect up... Any suggestions on how to get around this?

     

  • Saturday, November 07, 2009 1:54 AMChris Restall Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    Success!  Made a few changes to the config and things are now working with a custom X509CertificateValidator.  Here's the class:
    public class MyCertificateValidator : X509CertificateValidator
        {        
            private const X509RevocationMode ChainTrustRevocationMode = X509RevocationMode.NoCheck;
            private const StoreLocation AuthorityCertStoreLocation = StoreLocation.LocalMachine;
            private const StoreName AuthorityCertStoreName = StoreName.Root;
            private const string AuthorityCertThumbprint = "thethumbprintofmyCAcert";
    
             static MyCertificateValidator()
            {
                X509ChainPolicy policy = new X509ChainPolicy();
                policy.RevocationMode = ChainTrustRevocationMode;
            }
    
            public override void Validate(X509Certificate2 certificate)
            {
                           
                if(certificate==null)
                    throw new SecurityTokenValidationException("No Certificate was passed");
    
                X509Store store = new X509Store(AuthorityCertStoreName, AuthorityCertStoreLocation);
                
                store.Open(OpenFlags.ReadOnly);
                X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, certificate.IssuerName.Name, true);
                if (certs.Count != 1)
                    throw new SecurityTokenValidationException("Cannot find the root authority certificate");
    
                X509Certificate2 rootAuthorityCert = certs[0];
                if (String.Compare(rootAuthorityCert.Thumbprint, AuthorityCertThumbprint, true) != 0)
                    throw new SecurityTokenValidationException("Not signed by our certificate authority");
    
                store.Close();
            }
        }
    
    The service host config is the same as above with a change to the behaviors:
    <serviceBehaviors>
            <behavior name="chainBehavior">
              <serviceDebug includeExceptionDetailInFaults="True" />
              <serviceSecurityAudit messageAuthenticationAuditLevel="SuccessOrFailure" serviceAuthorizationAuditLevel="SuccessOrFailure" auditLogLocation="Application"/>
              <serviceCredentials>
                <clientCertificate>
                  <authentication certificateValidationMode="Custom" customCertificateValidatorType="Security.MyCertificateValidator, Security" trustedStoreLocation="LocalMachine" revocationMode="NoCheck" />
                </clientCertificate>
                <serviceCertificate findValue="My Client Cert" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />
              </serviceCredentials>
            </behavior>
          </serviceBehaviors>
    

    Likewise on the client:

    <endpointBehaviors>        
            <behavior name="chainBehavior">
             <clientCredentials>
                <clientCertificate findValue="My Client Cert" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />
               <serviceCertificate>
                 <authentication certificateValidationMode="Custom" customCertificateValidatorType="Security.MyCertificateValidator, Security" trustedStoreLocation="LocalMachine" revocationMode="NoCheck"/>
               </serviceCertificate> 
             </clientCredentials>
            </behavior>
          </endpointBehaviors>
    
    Hope someone finds this useful as it was hard fought knowledge...