I have a WCF service self-hosted in a windows service environment that works fine over http; over https I am unable to get to one URL without seeing the windows login prompt when running the silverlight application (or just opening the page in IE). I am using the IPolicyRetriever interface to ensure that the ClientAccessPolicy.xml file is found for the Silverlight app. This is working correctly.
The service in question has two endpoints defined:
<service behaviorConfiguration="defaultBehavior" name="WCFServices.Scheduler">
<endpoint address="WCFServices/Scheduler/" binding="wsHttpBinding" bindingConfiguration="dBinding" contract="WCFServices.IScheduler" />
<endpoint address="" binding="webHttpBinding" contract="WCFServices.IPolicyRetriever" behaviorConfiguration="PolicyBehavior" bindingConfiguration="dBinding" />
<host>
<baseAddresses>
<add baseAddress="https://myservername.org/" />
</baseAddresses>
</host>
</service>
If I go to the https://myservername.org/ I see the test service frontend (with a link to the wsdl). This is exposing the root IPolicyRetriever instance that the Silverlight app uses to pull down the policy file. I can load this and other URLs that expose the WCF service without any login prompts. BUT if I go to https://myservername.org/WCFServices/Scheduler/ in IE 8 I am greeted with a windows login. If I reset the security settings on the service and client to use http, I am able to do go to the latter url without the login prompt, and the silverlight app functions as expected. I suspect it has something to do with this WCF service being the only one with two endpoints defined (this windows service hosts 5 other WCF services, all of which only have 1 endpoint defined). Am I missing some authorization rules? I don't understand how that can be because all the other services load without prompts.
I would appreciate any help. I need the full https://myservername.org/WCFServices/Scheduler/ to serve the WCF service without asking for a login. Thanks for taking the time to read this.
As far as security, I only have this as my binding:
<binding name="dBinding" maxBufferPoolSize="524288" maxReceivedMessageSize="6553600">
<security mode="Transport">
</security>
</binding>
This issue was resolved by adding these lines to my security binding:
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None"/>
</security>
...but that led to a host of other issues, all of which I've been able to handle thanks to WCF logging. If you run into a NOT FOUND (400) error when debugging your WCF service, don't believe it. Turn on server side debugging and pour through the generated log files -- you'll get to the bottom of it.
I should also note that I've found the second endpoint to return a bad request (400) when opening in a web browser, and this is BY DESIGN. The first endpoint will list all additional endpoints in its wsdl, and you can still use any of them in a proxy generating tool. Don't worry if you're getting a bad request error when trying to access them directly in a browser.
Related
Just to put some context.
ASP.NET MVC2
Web API 5
IIS 7
I am trying to use the WCF Web API and as soon as I enable HTTPS, it stop working.
Things I noticed:
My API call I do through jquery, and I have something like this as the url:
http://www.domain.com/api/serviceApi/SetForeignToken?token=ASDAS-ASDAS-ASDASD-ASDASDAS&foreignToken=AS123ASD
When I use the API test UI I through:
https://www.domain.com/api/serviceApi/Test
I see for the test url:
https://devserver.ad.domain.com/api/serviceapi/SetForeignToken?token=ASDAS-ASDAS-ASDASD-ASDASDAS&foreignToken=AS123ASD
It just seems od the it resolves the DNS to the machine name instead of keeping the normal DNS, as it did before without HTTPS.
Does anyone know how to configure the API to make this work unde HTTPS, or is it even possible?
Thanks,
PS. The Development Enviroment has a self-signed certificate while the production will have a real certificate.
Yes, WCF Web API supports HTTPS. I believe there are a couple of ways to do this (including a code option). I only wanted https enabled on one server so I did this in my web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true">
<baseAddressPrefixFilters>
<add prefix="https://subdomain.example.com"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
<bindings>
<webHttpBinding>
<binding>
<security mode="Transport" />
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
Thanks guys. spent whole day figuring out this. Just added the code in web.config and it worked.
I've got a WCF service that is to be called by an application hosted on the web server (for the short-medium term, we'll only need a single web server so disregard scalability issues)
The web server serves a public website. at example.com
The WCF service exposes calls which amongst other things run jobs and provide certain admin functionality not supported by the web model eg long running database operations.
The WCF service has to be hosted inside the web site as it uses compatibility mode to take advantage of the Asp.Net http(s) pipeline - specifically, the service can generate emails and the emails are templated using MVC. One side-effect of this is that the call has to use the publicly visible hostname eg https://example.com/JobService.svc so that links in emails point to example.com as opposed to localhost or similar.
Obviously, I don't want the general public to be able to kick off jobs/admin tasks so I want to secure the WCF service.
I can only use https as opposed to net.tcp or similar for the binding thanks to relying on the Asp.net http pipeline.
I have to bind to the publicly accessible IP address to be able to use the proper hostname (unless someone knows a way around this?)
I can't use kerberos/NTLM as the server isn't on a domain (and NTLM is weak anyway)
I can't use certificates as it complains:
The SSL settings for the service 'SslRequireCert' does not match those of the IIS 'None'.
NB: I don't quite understand this as the website itself is only served via https. http simply returns a redirect to the same page via https.
(An interesting issue I'm having is that although the mex is served via https, the URLs inside the WSDL use http. I'm assuming this is a side-effect of not being able to set up TLS properly on my service so it thinks it's http even though it also responds on https)
So, I'm running out of ideas for how to secure my service. I could, of course, from within the service itself examine the request and determine if it comes from an IP used by the current server - but this feels very nasty and I'm effectively ignoring the work of experts and trying to put something in its place - Not a very good place to start.
Can anyone suggest a way to limit access to this service to processes on the local machine?
I've attached my current config below. (This is currently giving me the certificate error mentioned above)
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="WebJobServiceHTTPBinding" openTimeout="00:10:00"
sendTimeout="00:10:00">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"
aspNetCompatibilityEnabled="true">
<serviceActivations>
<add relativeAddress="WebJob.svc"
service="MyApp.WebJobService"
factory="MyApp.WCFDIServiceHostFactory" />
</serviceActivations>
</serviceHostingEnvironment>
<services>
<service behaviorConfiguration="WebJobServiceBehavior" name="MyApp.WebJobService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="WebJobServiceHTTPBinding"
name="HTTPEndpoint" contract="MyApp.JobService.Common.IWebJobService" />
</service>
</services>
<standardEndpoints>
<mexEndpoint>
<standardEndpoint name="WebJobServiceMex" />
</mexEndpoint>
</standardEndpoints>
<behaviors>
<serviceBehaviors>
<behavior name="WebJobServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<serviceCertificate findValue="[Thumbprint of x509 cert used by website for SSL]"
storeName="Root" x509FindType="FindByThumbprint" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
"Can anyone suggest a way to limit access to this service to processes on the local machine?"
Run your service in a different web site in IIS, if you're not already.
You could bind your service in IIS to the internal network IP address which would allow internal LAN clients to access the service but not external clients.
Another binding option is to bind to a port that is not open on your firewall in order to allow access from internal clients only. Even better, bind to a port that is not open on your firewall, and bind to the internal LAN IP.
You could also try binding to IP address 127.0.0.1.
In the end, I was forced to implement my own Authentication system. This was relatively simple as authenticatio implied authorization - ie no permission levels. That said, I'm still unhappy at the solution and will change it if another option presents itself.
When I deployed my WCF Data Services to production hosting I started to get the following error (or similar depending on which auth schemes are active):
IIS specified authentication schemes
'Basic, Anonymous', but the binding
only supports specification of exactly
one authentication scheme. Valid
authentication schemes are Digest,
Negotiate, NTLM, Basic, or Anonymous.
Change the IIS settings so that only a
single authentication scheme is used.
Apparently WCF Data Services (WCF in general?) cannot handle having more than once authentication scheme active.
OK so I am aware that I can disable all-but-one authentication scheme on the web application via IIS control panel .... via a support request!!
Is there a way to specify a single authentication scheme on a per-service level in the web.config?
I thought this might be as straight forward as making a change to <system.serviceModel> but... it turns out that WCF Data Services do not configure themselves in the web config. If you look at the DataService<> class it does not implement a [ServiceContract] hence you cannot refer to it in the <service><endpoint>...which I presume would be needed for changing its configuration via XML.
P.S. Our host is using II6, but both solutions for IIS6 & IIS7 appreciated.
Firstly it is possible to configurate Data Services on the web config file. The contract used by the DataService is called System.Data.Services.IRequestHandler.
Here is what you can do in the web config file to configurate it.
On the Service tag of the system.servicemodel element add the
<service name="{you service type name including the namespace i.e. myapplication.myservice}">
<endpoint address="" binding="webHttpBinding" contract="System.Data.Services.IRequestHandler">
</endpoint>
</service>
Once you have that there you can start configuring all manners of thing using the standard WCF configuration elements.
Secondly to enable or disabled authentication methods for a specific service in IIS you can do the following:
On the snap in for IIS right click your service file (i.e. yourservice.svc) and click properties.
Once in properties go to File Security Tab and chose the Edit button on the authentication and access control group box. after that it is just like setting up directory security in IIS.
As a last suggestion as per any trouble shooting goes it is important to enable the wcf disgnostics while you configurate it using the xml configuration, being written in WCF, Data Service logging is as per wcf is rich and very informative.
you can find out more about that on WCF Administration and Diagnostics
I hope i was able to help you with your problem
let me know how things goes.
Regards
Daniel Portella
UPDATE:
Hi Schneider
To specify the authentication scheme in the xml read below
For windows authentication as a example
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="MyBindingName" >
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="{you service type name including the namespace i.e. myapplication.myservice}">
<endpoint address="" binding="webHttpBinding" bindingConfiguration="MyBindingName" contract="System.Data.Services.IRequestHandler">
</endpoint>
</service>
</services>
</system.serviceModel>
</configuration>
For other types of authentication please check the MSDN library for examples
Common Scenarios for security
We have a system where the users access a web server, the web server then calls a WCF service.
We would like the call to the WCF service to be made in the security context of the windows identity of the application pool on the web server.
What is the best way to do this? Can it be done purely through configuration in the web.config file.
Thanks
Shiraz
Yes, you should be able to do this, all in config:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="WinAuth" mode="Transport">
<transport clientCredentialType="Windows" />
<bindings>
</netTcpBinding>
</bindings>
</system.serviceModel>
Of course, depending on your binding, you'd have to use a different tag under the <bindings> parent node - and of course, not all bindings support all security modes.....
In your endpoint, use the appropriate binding and then just reference this config:
<endpoint name="WCFService" address="......."
binding="netTcpBinding"
bindingConfiguration="WinAuth"
contract="......" />
That should do it! And of course, if you need message security instead of transport security, you can do that, too.
In your WCF service method, you can check to see whether or not the Windows credentials have been sent over, and what they are, by checking:
ServiceSecurityContext.Current.WindowsIdentity
This will be NULL if you don't have a Windows caller, otherwise it will show who called you.
Marc
I have a client/server application that has many client machines and one service on a server.....
On the server side I will be using a Windows Service to host my WCF service. The service will be passing data across the internet to the client machines. I figure I will be using wsHttpBinding with message level security, which requires a username or a certificate.
Now here's the problem.....
-We don't want to have the user log in to the system
-there is no Windows Authentication on the client machines
-and I would use certificates but, we have tons of client machines going out everyday, so installing certificates manually on each machine is not gonna be an option (unless it can all be done through code... and I mean creation and installing)
anybody have any ideas on how to secure this kind of service? Thanks in advance
Peace
In your scenario, it seems like you're looking for the "basicHttpBinding" with no security whatsoever.
<bindings>
<basicHttpBinding>
<binding name="NoSecurity">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
and then configure your endpoints to use that binding configuration:
<system.serviceModel>
<services>
<service name="YourNamespace.YourService"
behaviorConfiguration="MyServiceBehavior">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="NoSecurity"
contract="YourNamespace.IMyService">
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
There's also a really good blog post series that talk about the basics of WCF security in terms of five different, typical scenarios - excellent read! Your scenario would be the "No security at all" scenario.
Another good introductory article is Michele Leroux Bustamante's Fundamentals of WCF Security.
A more thorough (but also more complex) set of guidance for WCF can be found at the WCF Security Guidance on Codeplex.
Marc
Since you will be using an app wirtten by yourself. You can use wshttpbinding with username and password authentication (Client credential type basic) where your app reads the username and password from a config file.
http://msdn.microsoft.com/en-us/library/ms731299.aspx
EDIT
The windows service could run under an account that the user does not have the password for. The service is in a directory that is protected with ACLs, such that the user of the machine does not have access to the config file.