2

I've got a WCF enabled Windows service on our server which I'd like to consume. Both server and client should have appropriate certificates in their stores so these certificates can be used to secure the communication.

I'm not very experienced in WCF configuration and it turns out to be a nightmare with lots of different settings and elements, not all of them documented as good as I would have wished.

The relevant part of my current client configuration is as follows (seems that the code formatting doesn't work propertly on my version of IE I have to use, hopefully I'll fix that later at home):

<configuration>
<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="wsHttpBinding">
                <security mode="Message">
                    <message
                        clientCredentialType="Certificate"
                        negotiateServiceCredential="false"
                        algorithmSuite="Default" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
    <behaviors>
        <endpointBehaviors>
            <behavior name="wsHttpCertificateBehavior">
                <clientCredentials>
                    <clientCertificate
                        findValue="MyCert"
                        storeLocation="LocalMachine"
                        storeName="My"
                        x509FindType="FindBySubjectName"/>
                    <serviceCertificate>
                        <authentication
                            certificateValidationMode="PeerOrChainTrust"
                            revocationMode="NoCheck"
                            trustedStoreLocation="LocalMachine"/>
                    </serviceCertificate>
                </clientCredentials>
            </behavior>
        </endpointBehaviors>
    </behaviors>
    <client>
        <endpoint
            address="http://someserver:1234/wcf/service/"
            behaviorConfiguration="wsHttpCertificateBehavior"
            binding="wsHttpBinding"
            contract="SomeNamespace.ISomeInterface"
            name="wsHttpEndpoint">
            <identity>
                <servicePrincipalName value="what to put here?"/>
                <certificateReference 
                    findValue="MyCert" 
                    storeLocation="LocalMachine" 
                    storeName="My" 
                    x509FindType="FindBySubjectName"/>
            </identity>
        </endpoint>
    </client>
</system.serviceModel>

The server configuration is like this:

<?xml version="1.0"?>
<configuration>
<system.web>
    <compilation debug="true"/>
</system.web>
<system.serviceModel>
    <services>
        <service
            name="Os2CentralWcf.CentralAdUserManager"
            behaviorConfiguration="wsHttpCertificateBehavior">
            <host>
                <baseAddresses>
                    <add baseAddress="http://someserver:1234/wcf/service/"/>
                </baseAddresses>
            </host>
            <endpoint
                address=""
                binding="wsHttpBinding"
                bindingConfiguration="wsHttpEndpointBinding"
                contract="SomeNamespace.ISomeInterface"
                name="wsHttpEndpoint">
                <identity>
                    <dns value="MyCert"/>
                </identity>
            </endpoint>
            <endpoint
                address="mex"
                binding="mexHttpBinding"
                contract="IMetadataExchange"
                name="mexEndpoint"/>
        </service>
    </services>

    <bindings>
        <wsHttpBinding>
            <binding name="wsHttpEndpointBinding">
                <security mode="Message">
                    <message
                        establishSecurityContext="false"
                        negotiateServiceCredential="false"
                        clientCredentialType="Certificate"/>
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>

    <behaviors>
        <serviceBehaviors>
            <behavior name="wsHttpCertificateBehavior">
                <serviceMetadata
                    httpGetEnabled="true"
                    httpsGetEnabled="false"/>
                <serviceDebug includeExceptionDetailInFaults="true"/>
                <serviceAuthorization principalPermissionMode="None"/>
                <serviceCredentials>
                    <clientCertificate>
                        <authentication
                            certificateValidationMode="PeerOrChainTrust"
                            revocationMode="NoCheck"/>
                    </clientCertificate>
                    <serviceCertificate
                        findValue="MyCert"
                        storeLocation="LocalMachine"
                        x509FindType="FindBySubjectName"/>
                </serviceCredentials>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

When not specifying a servicePrincipalName in the client's configuration, I get the following:

System.ServiceModel.Security.MessageSecurityException: Client cannot determine the Service Principal Name based on the identity in the target address 'http://someserver:1234/wcf/service' for the purpose of SspiNegotiation/Kerberos. The target address identity must be a UPN identity (like acmedomain\alice) or SPN identity (like host/bobs-machine).

When trying to add such an element (e.g. <servicePrincipalName value=HOST/someserver:1234"/>, as suggested in the post referred to below), I end up with:

System.ServiceModel.Security.SecurityNegotiationException: Secure channel cannot be opened because security negotiation with the remote endpoint has failed. This may be due to absent or incorrectly specified EndpointIdentity in the EndpointAddress used to create the channel. Please verify the EndpointIdentity specified or implied by the EndpointAddress correctly identifies the remote endpoint.

Now my actual question is whether I have to use the identitysub element at all (the error message seems to indicate this, but I don't understand why). I also couldn't find any detailed documentation about what to put in the dns element and how to specify a servicePrincipalName (if really needed - this post didn't really help either).

Running both client and server (service) locally within Visual Studio 2010 works fine. I hope I supplied enough information, otherwise please feel free to ask - Unfortunately WCF configuration seems to be quite confusing if you start digging deeper into it...

Update

Using basicHttpBinding at the moment to be able to get both parties to communicate with each other works fine, locally as well as on the server.

Community
  • 1
  • 1
Gorgsenegger
  • 7,356
  • 4
  • 51
  • 89

1 Answers1

0

This exception can be fixed,it is really weird.You can get rid of it by adding a line to your App.config or Web.config .

<endpoint  address ="" binding ="wsHttpBinding" contract="System.ServiceModel.Routing.IRequestReplyRouter">
      <identity >
           <dns value ="localhost"/>
      </identity>
</endpoint>

Adding this line worked for me.. The identity tag in endpoint section will. Hope this helps

Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
ALLSYED
  • 1,523
  • 17
  • 15