But it works on my PC!

The random thoughts of Richard Fennell on technology and software development

Fixing a WCF authentication schemes configured on the host ('IntegratedWindowsAuthentication') do not allow those configured on the binding 'BasicHttpBinding' ('Anonymous') error

Whilst testing a WCF web service I got the error

The authentication schemes configured on the host ('IntegratedWindowsAuthentication') do not allow those configured on the binding 'BasicHttpBinding' ('Anonymous'). Please ensure that the SecurityMode is set to Transport or TransportCredentialOnly. Additionally, this may be resolved by changing the authentication schemes for this application through the IIS management tool, through the ServiceHost.Authentication.AuthenticationSchemes property, in the application configuration file at the <serviceAuthenticationManager> element, by updating the ClientCredentialType property on the binding, or by adjusting the AuthenticationScheme property on the HttpTransportBindingElement.

Now this sort of made sense as the web services was mean to be secured using Windows Authentication, so the IIS setting was correct, anonymous authentication was off

image

Turns out the issue was, as you might expect, an incorrect web.config entry

  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="windowsSecured"> <!—this was the problem –>
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" />
          </security>
        </binding>
      </basicHttpBinding>
  </bindings>
    <services>
      <service behaviorConfiguration="CTAppBox.WebService.Service1Behavior" name="CTAppBox.WebService.TfsService">
        <endpoint address="" binding="basicHttpBinding"  contract="CTAppBox.WebService.ITfsService">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="CTAppBox.WebService.Service1Behavior">
          <!-- To avoid disclosing metadata information, set the value below to false 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>

The problem was the basicHttpBinding had a named binding windowsSecured and no non-named default. When the service was bound to the binding it did not use the name binding, just the defaults (which were not shown in the config file).

The solution was to remove the name="windowsSecured" entry, or we could have added a name to the service binding

How to expose IIS Express to external network connections and use a non-self signed certificate

IIS Express is a great addition to the tools for .NET web developers; it allow a slightly cut down copy of IIS 7.5 to be run without administrative privileges on a developer’s PC. This means we can hopefully get away from the problems associated by either

  1. Using Cassini – which is not IIS and does not do any clever
  2. Using full IIS which means Visual Studio has to run as administrator to debug it and also causes source control issues when a project is shared between multiple developers (their IIS setup must match up)

If you install Visual Studio 2010 SP1 and IIS express you now get a new option, that is to use IIS express as your web server. This, via a few clicks, can be configured for SSL and should address 90%+ of the needs of most developers. Once a project is set to use IIS express the key properties are set via the VS Property windows

image

However you are not limited to only editing these options; but to do more you need to use some command line tools.

What I wanted to do

My problem was that I wanted to test a Windows Phone 7 application that used a WCF web service. If I switched the WCF project to use IIS Express the WP7 application could not access the web server as, for security reasons, IIS Express is by default limited to only responding to requests from the localhost. The WP7 application is on another device (or at least a VM for development), so its request are not handled.

So we need to enable remote access to the server. ScottGu said this can be done in his post about IIS Express, but not how to do it.

Also I wanted to test my WP7 application using HTTPS. This raised a second issue. By default IIS express uses a self signed certificate. When this is used the WP7 WCF client throws as error as it cannot validate the certificate. I needed to swap the certificate for a ‘real one’. Again ScottGu’s post says it can be done but not how.

How I got it working

NOTE: I think the process covers all the steps, but it took me a while to get this going so there is a chance I might have missed step. Please treat this as outline guide and not definitive way to get it going. if I find errors I will update the post and highlight them.

Step 1 – Get the right Certificate onto the Development PC

I had already installed  the wildcard SSL certificate we have on my development PC from ita .PFX file.

To confirm this was OK I load MMC (running as a local administrator). Loaded the certificates snap-in, browsed to Personal|Certificates and checked it was there. I then clicked on the certificate and made a note of its thumbprint, you need it later

image

Step 2 – List the certificates you have installed for IIS

I opened a command prompt as administrator and run the command

netsh http show sslcert

This will stream past so you probably want to pipe it into a file to look at. Anyway you should find an entry for the self sign certificate that Visual Studio created when you setup IIS Express (on port 44300 in my case). Something like

IP:port                 : 0.0.0.0:44300
    Certificate Hash        : c3a234250edfb2adcd2b501cf4c44d0281e29476
    Application ID          : {214124cd-d05b-4309-9af9-9caa44b2b74a}
    Certificate Store Name  : MY
    Verify Client Certificate Revocation    : Enabled
    Verify Revocation Using Cached Client Certificate Only    : Disabled
    Usage Check    : Enabled
    Revocation Freshness Time : 0
    URL Retrieval Timeout   : 0
    Ctl Identifier          : (null)
    Ctl Store Name          : (null)
    DS Mapper Usage    : Disabled
    Negotiate Client Certificate    : Disabled

We need to remove this self signed certificate so we can re-assign a real one to this port. To do this use the command

netsh http delete sslcert ipport=0.0.0.0:44300

then add the new certificate association using the command

netsh http add sslcert ipport=0.0.0.0:44300 certstorename=MY certhash=<certificate hash> appid=<appid>

<certificate hash> is the thumbprint of the SSL certificate found in step 1, with the spaces removed
<appid> can be any unique GUID

if you have the command line right it should say added OK. You could then run the list command again to check it is as you want.

So where are we up to…..

So at this point we have associated a real SSL certificate with any call to the port 44300 on this PC, note any call to this port, not just for IIS Express. If we do nothing else to configure IIS Express, let Visual Studio automatically start it, and try to load the site it will work for HTTP but when you try HTTPS it will error

image

If you inspect the certificate you will see it is using the one you set, but the certificate is linked to a Url, in my case *.blackmarble.co.uk so is deemed invalid when you try to use it with localhost.

We need to set IIS Express to respond on other addresses than localhost.

Step 3 – Making IIS Express respond to requests from the network

If you wish to make IIS Express respond to calls other than for localhost you have to run it as administrator, this is by design for security. Now it is fair to say from here onwards you are at the point where you lose some of the ease of use of the product as it does not ‘just work form Visual Studio’, but needs must.

We now need to edit the bindings of IIS Express. This could be done with command

c:\program files\iis express>appcmd set site "SiteName" /+bindings.[protocol='https', bindingInformation='*:44300:']

But I found it easier just to edit the edit the file C:\Users\[user name]\Documents\IISExpress\config\applicationhost.config in notepad. I altered the bindings section as follows

<bindings>
      <binding protocol="http" bindingInformation="*:60213:" />
      <binding protocol="https" bindingInformation="*:44300:" />
</bindings>

Basically I removed the :localhost at the end of each line. This allowing IIS Express to bind any Url not just localhost

Step 4 – Running IIS Express

You now need to just start your copy of IIS Express, this again has to be done from the command prompt running with administrative privileges. However, the command line parameters are identical to those used by Visual Studio (you can check task manager if you wish by showing the command line column on the processes tab)

"c:\Program Files (x86)\IIS Express\iisexpress.exe" /config: "c:\Documents and Settings\[username]\Documents\IISExpress\config\applicationhost.config" /site:"MyServer" /apppool:"Clr4IntegratedAppPool"

When you run this you should see the IIS Express process start-up.

So what have we ended up with?

So we now have IIS Express running the a wildcard certificate and listening to requests from any source. So as long as we use a Url valid for the SSL certificate we should be be able to load an HTTPS Url and get no errors.

However, be warned, due to the way we have had to launch IIS Express we have lost the ability to launch and debug from Visual Studio when not running as administrator. So I am not sure I have addressed the problem I started out try to address, I might as well just use the full version of IIS.

But look on the bright side I learnt something.

Thanks to Andy Westgarth for his assistance in getting to the bottom of assigning the right certificate, I was going in circles

[More] Fun with WCF, SharePoint and Kerberos

This is a follow up to the post Fun with WCF, SharePoint and Kerberos – well it looks like fun with hindsight

When I wrote the last post I thought I had our WCF Kerberos issues sorted, I was wrong. I had not checked what happened when I tried to access the webpart from outside our TMG firewall. When I did this I was back with the error that I had no security token. To sort this we had to make some more changes.

This is the architecture we ended  with.

image

The problem was that the Sharepoint access rule used a listener in TMG that was setup to HTML form authentication against our AD

image

and the rule then tried to authenticate our Sharepoint server via Kerberos using the negotiated setting in the rule. This worked for accessing the Sharepoint site itself but the second hop to the WCF service failed. This was due to use transitioning between authentication methods.

The solution was to change the access rule to Constrained Kerberos (still with the same Sharepoint server web application SPN)

image

The TMG gateway computer (in the AD) then needed to be set to allow delegation. In my previous post we had just set up any machines requiring delegation to ‘Trust this computer for delegation to any service’. This did not work this time as we had forms authentication in the mix. We had to use ‘Trust this computer for delegation to specific services only’ AND ‘use any authentication protocol’. We then added the server hosting the WCF web service and the Sharepoint front end into the list of services that could be delegated too

image

So now we had it so that the firewall could delegate to the Sharepoint server SPN, but this was the wrong SPN for the webpart to use when trying to talk to the WCF web service. To address this final problem I had to specifically set the SPN in the programmatic creation of the WCF endpoint

this.callServiceClient = new CallService.CallsServiceClient(
    callServiceBinding, 
    new EndpointAddress(new Uri("http://mywcfbox:8080/CallsService.svc"), EndpointIdentity.CreateSpnIdentity("http/mywcfbox:8080")));

By doing this a different SPN is used to connect to the WCF web service (from inside the webpart hosted in Sharepoint) to the one used by the firewall to connect to the Sharepoint server itself.

Simple isn’t it! The key is that you never authenticated with the firewall using Kerberos, so it could not delegate what it did not have.

Getting a ,NET 4 WCF service running on IIS7

Now I know this should be simple and obvious but I had a few problems today publishing a web service to a new IIS7 host. These are the steps I had to follow to get around all my errors:

  1. Take a patched Windows Server 2008 R2, this had the File Server and IIS roles installed.
  2. I install MSDeploy (http://blog.iis.net/msdeploy) onto the server to manage my deployment, this is a tool I am becoming a big fan of lately.
  3. Make sure the MS Deploy service has started, it doesn’t by default.
  4. In IIS manager
    1. Create a new AppPool (I needed to set it to .NET 4 for my application)
    2. Create a new Web Site, pointing at the new AppPool
  5. In Visual Studio 2010 create an MSDeploy profile to send to the new server and web site. This deployed OK
  6. AND THIS IS WHERE THE PROBLEMS STARTED
  7. When I browsed to my WCF webservice e.g.http://mysite:8080/myservice.svc whilst on the server I got a ‘500.24 Integrated Pipeline Issue’ error. This was fixed by swapping my AppPool’s pipeline mode to Classic, as I did need to use impersonation for this service.
  8. Next I got a ‘404.3 Not Found’ error. This was because the WCF Activation feature was not installed in the box. This is added via Server 2008 : Server Manager -> Add Features-> .Net Framework 3.x Features -> WCF Activation
  9. Next it was a ‘404.17 Not Found Static Handler’. If I looked in IIS Manager, Feature View, Handler Mapping I only saw mention on 2.0 versions of files. So I reran aspnet_iisreg /i from the 4.0 framework directory and both 2.0 and 4.0 versions were shown in the Handler list
  10. Next it was a ‘404.2 Not Found. Description: The page you are requesting cannot be served because of the ISAPI and CGI Restriction list settings on the Web server’. In the IIS Manager at the server level I had to enable the .NET 4 handlers in ISAPI and CGI restriction section
  11. I could then get to see the WSDL for the WCF service
  12. And finally I had to open port 8080 on the box to allow my clients to see it.

Now that was straight forward wasn't;t it.