tags:

views:

7814

answers:

6

My WCF Service uses wsHttpBinding and works fine from the client when the service is gerenated by the client using the default options as follows:

        RServiceClient R = new RServiceClient();

However, at some point I'll need to be able to specify the location of the service, presumably by changing the endpoint address as follows:

        RServiceClient R = new RServiceClient();
        R.Endpoint.Address = new EndpointAddress(new Uri "http://xxx.xxxx.xxx:80/RServer/RService.svc"));

However, when I do specify the exact endpoint, I get a SecurityNegotiationException: System.ServiceModel.Security.SecurityNegotiationException was unhandled Message="The caller was not authenticated by the service." Source="mscorlib"....

The WCF service runs on IIS and has anonymous access enabled under IIS admin. Also, this error occurs when the client is run from the same machine as the service under an admin account - I havn't got to the scary part of running it over the net yet!

Any Ideas?

A: 

Are you using MessageSecurity with certificates? this could be a certificate issue (wrong hostname, self-signed certificate not installed, etc..)

Joachim Kerschbaumer
A: 

Here is my Service configuration information, i'm using wshttpbinding:

<system.serviceModel>
 <services>
  <service behaviorConfiguration="ServiceBehavior" name="RService">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration=""
 name="RService" contract="IRService">
 <identity>
  <dns value="localhost" />
 </identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" name="MetadataExchange"
 contract="IMetadataExchange" />
   </service>
</services>
 <behaviors>
  <serviceBehaviors>
   <behavior name="ServiceBehavior">
    <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
    <serviceMetadata httpGetEnabled="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>
 </behaviors>
</system.serviceModel>
Calanus
+2  A: 

check this from your config :

...    
     <identity>
      <dns value="localhost" />
     </identity>
...

afaik wsHttpBinding has message security turned on by default. and when it checks against the dns value "localhost" it fails.

Joachim Kerschbaumer
A: 

Deleting the identity block didn't work, although did give me an idea: If I change the endpoint address from:

        R.Endpoint.Address = new EndpointAddress(new Uri("http://bigpuss.homeip.net/RServer/RService.svc"));

to

        R.Endpoint.Address = new EndpointAddress(new Uri("http://localhost/RServer/RService.svc"));

then everything works fine! Soo, its obviously upset about the nonlocal url address. Are there any other areas in the configuration where security is set up?

Calanus
+2  A: 

I think by default wsHttpBinding uses Windows authentication. I'm not sure how hosting in IIS affects that scenario.

If you don't want security turned on, you can add an element for security and set the mode element to "None" to the config on both ends to turn off the default setting.

I think this may do the trick -- I've added the section for wsHttpBinding and set the bindingConfiguration of your service to point to the newly added binding properties:

<system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="wsHttpBind">
          <security mode="None">
            <transport clientCredentialType="None" protectionLevel="EncryptAndSign" />
            <message clientCredentialType="None" algorithmSuite="Default" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
     <service behaviorConfiguration="ServiceBehavior" 
      name="RService">
      <endpoint address="" 
       binding="wsHttpBinding" 
       bindingConfiguration="wsHttpBind" 
       name="RService" 
       contract="IRService"> 
       <identity>
        <dns value="localhost" />
       </identity>
      </endpoint>
      <endpoint address="mex" 
       binding="mexHttpBinding" 
       name="MetadataExchange" 
       contract="IMetadataExchange" />
     </service>
    </services>
    <behaviors>
     <serviceBehaviors>
      <behavior name="ServiceBehavior">
      <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
       <serviceMetadata httpGetEnabled="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>
    </behaviors>
</system.serviceModel>
Mike L
A: 

Thanks Mike, That helped alot and has enabled me to fix the problem. It did complain about the protectionLevel="EncryptAndSign", saying that that was not a valid attribute in the web.config, but once that was removed all was ok.

If I did want the message to be encrypted (but not authenticated), how would I go about doing this? I tried adding:

[ServiceContract (SessionMode=SessionMode.Required, ProtectionLevel=ProtectionLevel.EncryptAndSign)]

to my contract, but when I update the Srevice Reference in the client it says "the request message must be protected...the protection must be provided by the binding. Not really sure what this means though...do I need to add something to the client proxy configuration?

Calanus
I imagine protectionLevel attribute is OK in app.config, but not in web.config. I typically self-host in Windows Services, so I'm not as familiar with the way it hooks into IIS.
Mike L