I've asked a similar question here:
How to enforce one method in WCF Rest to be called via https, while others can be called over http
And it doesn't look like it is possible on the code side. Is it possible to set up an entire service to be callable over HTTPS only? I've configured a service using the following binding:
<webHttpBinding>
<binding name="webBinding"
maxBufferSize="152428800" maxReceivedMessageSize="152428800"
receiveTimeout="00:10:00">
<readerQuotas maxStringContentLength="152428800"
maxArrayLength="152428800"
maxBytesPerRead="4096"/>
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
But when I try to call a simple service over http, the service returns the result happily, rather than returning some sort of exception. Do I need to configure IIS to only service https requests? Has anyone tried this?
Thanks!
Did you configure IIS to require SSL on your application's folder? (you can set it to allow ssl or make it mandatory)
You can always add an explicit endpoint to your service entry with a fully-qualified https address. Can't remember if IIS hosting always auto-adds the base addresses when you have an explicit address, but even if it does, you can make a simple extension of ServiceHostFactory to "eat" the default base addresses IIS supplies (reference your custom servicehostfactory in the Factory attribute of your .svc file). Then it'll only answer on the exact addresses you supplied in the config.
It's possible via configuration. This Blog Article is not your exact scenario (it's file transfer over https), but it shows sample config and code for configuring and consuming a https web service that should be useful.
Related
Some clients need to be able to connect to our WCF SOAP services using Basic authentication, while others need to use Windows authentication. We normally host our services in IIS, although we do provide a less-developed Windows Service hosting option.
It's my understanding that it is not possible to configure one endpoint to support both Basic and Windows authentication. So we have two endpoints per service.
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicBinding" contract="SomeContract" bindingNamespace="http://www.somewhere.com/Something" />
<endpoint address="win" binding="basicHttpBinding" bindingConfiguration="WindowsBinding" contract="SomeContract" bindingNamespace="http://www.somewhere.com/Something" />
...
<bindings>
<basicHttpBinding>
<binding name="BasicBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
<binding name="WindowsBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
These are in the same Web Application in IIS. That Web Application has both Basic and Windows authentication enabled (else one of the above bindings wouldn't work).
When a client uses the Windows-authenticated endpoint (with "win" on the end of URL), this typically works fine. When the initial request doesn't contain any authentication information, a negotiation takes place between the client and IIS, they settle on Windows authentication and all goes well.
When a client uses the Basic-authenticated endpoint (without "win" on the end of URL), this works if they include the Authorization HTTP header with the correct encoded credentials in it. However, if they do not include any authentication information in the initial request, the negotiation ends up choosing Windows authentication. This gets the request past IIS security, but WCF then refuses the request, because it's going to a Basic-authenticated endpoint.
I am rather hazy on exactly what's happening in the negotiation. But it seems to me that IIS offers all authentication methods enabled for the Web Application (i.e. Basic and Windows), even though the particular WCF endpoint URL for the request only supports Basic.
I would like to know if there is anything we can do in IIS to make the negotiation come up with the right answer: that is, if the request is to a Basic-authenticated endpoint, tell the client to use Basic. Of course, we still want the negotiation to end up choosing Windows, when the request went to the Windows-authenticated endpoint.
If there isn't, then do you think we would be better off concentrating on our Windows Service-hosted version of the services? Or would that have similar problems somehow?
Final note: we do use Basic with HTTP for some internal uses, but we do know that this is an insecure combination. So we typically turn on HTTPS for production use; I've left that out here, for simplicity.
Yes, clientCredentialType="InheritedFromHost" solves the problem for me. This, new in .Net 4.5, means that one can now use the same endpoint URL for more than one authentication type. IIS settings control what authentication is allowed, meaning no longer possible to get IIS and WCF settings in conflict.
We have a WCF Data Service which is self-hosted under a Windows service (not using IIS) which we are currently working to secure using SSL and Windows Authentication.
After some time playing around with netsh and server certificates, we now have the service secured with SSL and we have also enabled Windows Authentication on the webHttpBinding in our app.config - however we are now seeing some strange behaviour when attempting to authenticate certain users - some can log in fine, others have their credentials rejected and are prompted with HTTP 400 errors.
After some testing and digging around it would appear that we might be running into this problem, where the authentication header used by Kerberos may be greater than the maximum permitted header length (which I believe is 16k) for certain users - and although there is a documented workaround for IIS, there does not appear to be an equivalent setting we can use for a self-hosted service, or in our app.config - unless I'm missing something? We tried setting the maxReceivedMessageSize and maxBufferSize fields to their maximum values to see if that would make any difference, but apparently not.
Binding config:
<webHttpBinding>
<binding name="DataServicesBinding"
maxReceivedMessageSize="2147483647"
maxBufferSize="2147483647">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
We've managed to work around this issue temporarily by setting the clientCredentialType in our binding to use Ntlm instead, but we'd like to get Kerberos working if possible for obvious reasons.
So, as it turns out, this was caused by our service not being configured with a SPN (Service Principal Name). This can be done using the setspn tool with Windows Server. (See this MSDN article for more information.)
Once the SPN was applied, Kerberos authentication started to work as expected.
Use wireshark to see what the client sends. Make sure that this input is correct and then come back.
TL;DR version is at the bottom.
I have constructed three WCF web services -- one that's using .NET 4 and two that's using .NET 3.5 -- that is consumed by an Android client. The Android client performs the calls using ksoap2-android. When the services were complete and the client could make all the calls and get all the data from the services, we decided to activate HTTPS communication for the web services. They are hosted on a server running IIS.
I'm not alone on this task. I work full-time with it, mainly the Android client. I have two coworkers, both of which have a lot of other responsibilities. The first is mostly involved in the services and the second is mostly involved in the server.
I've read a lot of guides, blogs and articles on the Internet on how to enable HTTPS for a WCF web service, but still I haven't been able to completely resolve this. For the Android client to be able to consume the client, we are limited to using the basicHttpBinding, since the wsHttpBinding contains some security details that are not supported by Android, or something. I'm not sure, but I read it some forum somewhere. If I'm wrong, I'd happily be corrected!
Okay, so I'll give a short account of what I've done so far:
I've enabled transport security, this is how the binding(s) looks:
<bindings>
<basicHttpBinding>
<binding name="basicHttp" closeTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
I've enabled meta data publishing over HTTPS using this line of code:
<serviceMetadata httpsGetEnabled="true" />
and this:
<endpoint address="" binding="mexHttpsBinding" contract="IMetadataExchange" />
Also, my second coworker has installed a trusted certificate (a real certificate from a CA) on the IIS server and added a https binding on the server.
Okay, so far, so good. Now we could connect to the services in the browser.
When we had done this it was possible to visit the service in the browser in a secure, encrypted, manner.
The problem is that it isn't possible to make a call to the service, neither in Android nor WCF Test Client. If I call the service on the https address, I get a 404 in response. WCF Test Client returns this:
There was no endpoint listening at https://[my service address] that could accept the message. This is often caused by an incorrect address or SOAP action.
To be able to debug this, I'm using Wireshark to intercept the messages and see what really happens. I've found out that after the set up procedures (handshake, establishing trust etc.) the client sends the header and get a 101 Continue in response, after which it POSTs the body. This should be normal behavior. But then the service returns 404 Not Found. Wireshark says that the full request URI is the http address. I've configured the server to use the https address, so why does it make a call to the http address?
I've tried setting the address and listenUri attribute of the endpoint to https and http respectively and the other way around. If I do that, the server answers the request with 405 Method Not Allowed.
Is there any way to solve this? What am I missing?
What am I missing?
TL;DR version below
I'm hosting three WCF SOAP web services with IIS, one using .NET 4 and the others using .NET 3.5. I'm trying to make a call from the WCF Test Client over HTTPS. I've enabled transport security, meta data publishing over HTTPS, installed a trusted certificate and added a https binding on the server.
When I try to make a call from WCF Test Client it says that there was no endpoint listening at the address. Wireshark tells me it makes the call to the http version of the service (i.e. "http://[my address]" instead of "https://[my address]"), although it is configured to call the https address. The service returns 404 Not Found. If I set the address of the service to https and listenUri to http, I get 405 Method Not Allowed. If I do it the other way around it says that it cannot be activated. What am I missing?
I solved this by removing the endpoint and using the <protocolMapping> tag, like this:
<protocolMapping>
<add scheme="https" binding="basicHttpBinding" bindingConfiguration="basicHttps" />
</protocolMapping>
Am using the new VS2010 template for Rest Web Services, which sets up the service without an SVC file and with minimum config, and you set up the route in the global.asax.cs file.
On deploying my WCF Rest Service to test environment where its accessed by https, I get an exception: Could not find a base address that matches scheme http for the endpoint with binding WebHttpBinding. Registered base address schemes are [https].
Have found solutions to this on Scott's Blog and Taciturn Discourse
However these solutions are based on having the WCF being configured via the more traditional config route with full specification of endpoint address, binding, contracts.
In the simplified template approach, as we don't setup the endpoint ABC explicitly in config, then how can we fix this issue of the missing base address?
Sorted this out, because using https, need to specify that security is being set at the transport layer. So include this in the system.serviceModel config:
<bindings>
<webHttpBinding>
<binding>
<security mode="Transport" />
</binding>
</webHttpBinding>
</bindings>
My thanks to the two posts below that provided the solution, however found I did not need to put in all their recommendations to get it to work
Configuring WCF 4 with routing (global.asax) for both http & https endpoints
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/1dd991a1-e32f-4035-a406-994729858b40
Cheers, Mickey
I have the following binding I'm using with my wsHttpBinding webservice.
<binding name="wsHttpConfig">
<security>
<transport clientCredentialType="None"/>
</security>
</binding>
The issue is that it allows for the client to connect using either Http or Https. I would like to require them to use SSL. I tried adding the following:
<system.web.extensions>
<scripting>
<webServices>
<authenticationService enabled="true"
requireSSL = "true"/>
</webServices>
</scripting>
</system.web.extensions>
But it had no effect; client could still connect with Http. I then tried checking the "Require SSL" in the IIS7 SSL Settings and had client certificates radio set to Accept. Now, when I try to view the service I am getting the error "Could not find a base address that matches scheme http for the endpoint with binding WSHttpBinding. Registered base address schemes are [https]."
Anyone know exactly how to fix this error? I have been googling for the last 3 hours trying 500 different combinations (not 500, but too many to list) and could not get anything to run.
For anyone stumbling across this one from Google, Bing (Bingle, Yangle?) then take a look at a blog post a put together to help others trying to run a secure AuthenticationService in a test environment.
http://www.lukepuplett.com/2010/07/setting-up-wcf-over-ssl-on-iis-7x.html
And good luck!
Have you read this msdn post?
You must either change
binding="mexHttpBinding"
to
binding="mexHttpsBinding"
or else add an http base address in addition to the https base address. (Right now the metadata endpoint is trying to get hosted on http, rather than https, and there's no base address for that.)
Have you correctly configured your endpoint?
Have you tried dynamically configuring the base address?