I have a bunch of WCF services at a domain:
AuthenticationService (the standard MS one, over HTTPS)
AppService (HTTP)
Usually, I call the Authentication Service and a cookie is returned. For desktop applications, I detach the cookie and reattach it with every new service call to the AppService which exposes the meat of my API.
Silverlight in the browser automatically attaches the cookie in all calls to the domain. I expected the phone to do the same.
It doesn't.
Access to the headers is not supported on the phone, so manual manipulation is out. I wonder if its because some bright spark at MS thought that the phone should enforce that cookies are only reattached to HTTPS endpoints at the same domain or something...
Help!!
This is a nightmare to troubleshoot since the phone doesn't support the other major major helpful setting; ignoring self-signed certificates.
Thanks,
Luke
** UPDATE **
While I'm following up the method using CookieContainer I must point out that even though the Add method on the Headers collection is missing in Silverlight, one can still add headers using the indexer.
See http://cisforcoder.wordpress.com/2010/12/01/how-to-implement-basic-http-authentication-in-wcf-on-windows-phone-7/
** UPDATE 2 **
CookieContainer can be set as per Lex answer. I'm now stuck and continuing to investigate an ArgumentNullException thrown from within the WCF client upon References.cs EndInvoke. My server shows no sign of receiving the call.
Two key calls on the stack are:
System.Net.Browser.HttpWebRequestHelper.ParseHeaders
And
MS.Internal.InternalWebRequest.OnDownloadFailed
FINAL UPDATE
The ArgumentNullException seems to be thrown when called against a server with a self-signed certificate.
However, there's something odd with the emulator/SDK. I have had this exception against all my servers, even those with no SSL, and one with an issued certificate.
I've also had problems that have been resolved only by a local reboot. So I think my problems have been a result of having the right code, but thinking it was wrong because of other problems in the SDK.
Not sure what advice to give, except to be mistrusting of exceptions stemming from the WP7 WCF stack, particularly EndpointNotFoundException and ArgumentNullException, and to have a full framework test client app around as a sanity check.
Luke
In desktop SL, I do it by sharing cookie container between service proxies in client http stack. Did not try this on WP7, but you may check this out.
First, you need to insert <httpCookieContainer/> in your client-side binding configuration (usually in ServiceReferences.ClientConfig).
In code, switch to client http stack.
WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp);
Then you need to create a CookieContainer instance and assign it to all service proxies.
var cc = new CookieContainer();
var service1 = new ServiceReference1.MyService1Client { CookieContainer = cc };
var service2 = new ServiceReference2.MyService2Client { CookieContainer = cc };
Now, when your cookie container receives cookie, it will reuse it for all web services. Make sure, that cookie comes with correct Path setting.
Related
I'm new to IdentityServer4 (2.5) and certificate setup so please bear with me. I think that I've chased down everything I could. I am using it with ASP.Net Core 2.2.0 in a proof of concept app. I have OpenIdConnect with an authority app and a client using cookies with X509Certificate2. Works great on my local machine; however, when I deploy to IIS I get this error:
System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://my.com/mpauth/.well-known/openid-configuration'. ---> System.ArgumentException: IDX20108: The address specified 'http://my.com/mpauth/.well-known/openid-configuration/jwks' is not valid as per HTTPS scheme. Please specify an https address for security reasons. If you want to test with http address, set the RequireHttps property on IDocumentRetriever to false.
The problem is here - http://my.com/mpauth/.well-known/openid-configuration/jwks. If I put that in the browser I get an error; however, if I change http to https I get the data. What setting controls this?
TL;DR
In most cases IdentityServer defers the base hostname/URI from the incoming request but there might be deployment scenarios which require enforcing it via the IssuerUri and/or PublicOrigin options as documented here.
More Info
The URL you are getting in your exception is part of the discovery lookup. It is necessary for validating tokens (e.g. in an applications auth middleware).
There should be a first request to .../.well-known/openid-configuration (the main discovery document) that refers to several other URIs and one of them should be the jwks (signing key sets). In most cases the other URIs in openid-configuration will point to the same primary hostname and protocol scheme your identity server is using. In your case it looks like the scheme changes to HTTP which might be unwanted in this day and age.
Is it possible, that the deployed IdentityServer lives behind a load balancer/SSL termination appliance? This could cause behavior.
I am not sure about IIS details but there might also be some kind of default hostname/URI thing at play.
This may be a stupid question but I just can't find the answer.
What I would like to do:
I have a WCF service hosted by IIS. It is working perfectly, I can access the wsdl, I have a self-signed certificate for the server etc. I would like to call this service from a WPF client.
The problem is, since I have a self-signed certificate, I get the following exception when calling the service:
Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost'.
If I access the site (or the service) from a browser, it is no problem, because the browser warns me about the certificate, and gives me the choice of viewing the page anyway. But the WPF client just throws an exception.
I don't want to completely turn off the authentication process, I simply would like to give the users the option of ignoring this warning (as browsers do).
Can anyone provide some code for this? If you ran into a good, detailed tutorial about this, it would be awesome too. (See, my problem with the tutorials I've found is the lack of details)
Here's the minimum amount of code you need to make WCF client accept an arbitrary certificate. This is not secure. Use for testing only. Don't blame me if this code goes berserk and eats your little kitten.
ServicePointManager.ServerCertificateValidationCallback +=
new System.Net.Security.RemoteCertificateValidationCallback(EasyCertCheck);
The call back:
bool EasyCertCheck(object sender, X509Certificate cert,
X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
return true;
}
Code shamelessly lifted from the least helpful answer to Is it possible to force the WCF test client to accept a self-signed certificate?
You can register the certificate yourself. If load the certificate in the client as well, and then register the it as trusted you shouldn't get that warning.
You need to find a X509CertificateCollection and add the certificate to that collection. I had this kind of problem with a SmtpClient running over Ssl.
By hooking the System.Net.ServicePointManager.ServerCertificateValidationCallback or implementing System.Net.ICertificatePolicy and identify my own installed certificate as valid/trusted (attached to the System.Net.ServicePointManager.CertificatePolicy).
This is not WCF stuff per se, but from what I could tell, this should translate to WCF as well. It all depends what WCF is uses under the hood.
Ok,
I have developed this WinForms client, which interacts with a server (ASPX Application) by means of WCF calls. I would now like to deploy the server to my shared webhost, but I'm kinda new to WCF and especially the security possibilities behind it.
The goal is to kind of secure the WCF service, so that not everybody that knows or finds out the endpoint address can call it. Rather, only my WinForms client must be able to call the WCF service.
I do not need authentication on a user basis, so no authentication is required from the user of the client. But I want only instances of this WinForms client to be able to interact with the service. The information passed between server and client is not very sensitive, so it's not really required to secure it, but it's a plus if it can easily be done.
Is this possible with a Shared Host (IIS) environment (no HTTPS at disposal) ? What bindings and options should I use ? I suppose wsHttpBinding, but how would I setup the security options ?
Using .NET 4.0
Thanks
From what I understand, you have an internet-facing service which you want to limit to only your client app to be able to call - correct? Or do you envision other clients (like PHP, Ruby etc.) also wanting to call into your service at some point?
To secure your message, you have two options in WCF - message or transport security. Over the internet, with an unknown number of hops between your client and your service, transport security doesn't work - you're left with message security (encrypting the message as it travels across the 'net). For this to work, you typically add a digital certificate to your service (only server-side) that the client can discover and use to encrypt the messages with. Only your service will be able to decrypt them - so you're safe on that end.
The next point is: who can call your service? If you want to be totally open to anyone, then yes, you need wsHttpBinding (or the RESTful variant - webHttpBinding). If you want to allow non-.NET clients, you're typically limited to no authentication (anyone can call), or username/password schemes which you will validate on the server side against a database of valid users.
If you only want to allow your own .NET client in, then you can do several things:
disable metadata on your service; with this, you would "hide" your endpoints and the services they provide - someone using a "metadata scanner" (if that exists) wouldn't be able to just stumble across your service and find out what methods it provides etc. This however also makes it impossible for another developer outside your organization to do an Add Service Reference to your service.
you could define and use a custom binary http binding - only other clients with this setup could even call your service. The binary http binding would bring some speed improvements, too. See this blog post on how to do this.
you need to somehow identify those callers that are allowed in - one possible method would be to put an extra header into your WCF messages that you then check for on the server side. This would simply make sure that a casual hacker who discovers your service and figures out the binary http binding would still be rejected (at least for some time). See this blog post here on how to implement such a message inspector extension for WCF.
the ultimate step would be to install a digital certificate on the client machine along with your service. You would then set up your client side proxy to authenticate with the service using that certificate. Only client machine that have that certificate could then call into your service.
It really depends on how far you want to go - WCF gives you a lot of options, but you need to decide how much effort you want to put into that .
The first thing you need to ask your self is: "What can someone do to your WCF service if they connected their own customized client?" Look at all of the functionality that is being exposed via WCF and assume that it could be accessed at will. You have absolutely no control over the client, and you will never have this ability.
HTTPS is beautiful, its a damn shame that your forced to be vulnerable to OWASP A9: Insufficient Transport Layer Protection. If it where up to me, I would move to a different host that cared about security. If you are throwing usernames and passwords over the network, then your putting your users in danger.
One of the biggest problems I have seen with a WCF service is that they had a "executeQuery()" function that was exposed. The developer allowing the client to build queries to be executed by the server. This approach is fundamentally flawed as you are just handing your database over to an attacker. This type of vulnerability isn't SQL Injection, it falls under CWE-602: Client-Side Enforcement of Server-Side Security.
Along the same lines as CWE-602 is OWASP A4: Insecure Direct Object References. Could an attacker fool your WCF service into thinking its another user by providing a different user id? Are you trusting the client to tell the truth?
The next classification of vulnerabilities that you must take into consideration is OWASP A1: Injection, other wise known as "Taint and Sink". For instance if you are exposing a function where one of its parameters is being used in a CreateProcess() which is invoking cmd.exe. This parameter could be controlled by the attacker, and there for this variable is "tainted", the call to CreateProcess() is a "sink". There are many types of vulnerabilities along these lines, including but not limited to; SQL Injection, LDAP Injection, XPATH Injection. These types of vulnerabilities affect all web applications.
Can anyone point me in the right direction of how I can use SSL client-side certificates with Silverlight to access a restful web service?
I can't seem to find anything on how to handle them, or even whether they are supported.
Cheers.
Slipjig mentioned this:
"The browser stack does, and pretty much automatically, if you're willing to live with its other limitations (lack of support for all HTTP verbs, coercion of response status codes, etc.)."
If that is acceptable to you, look at how Microsoft themselves deal with this in some of their APIs using the custom X-HTTP-Method header, like how they do it for WCF and OData:
http://www.odata.org/developers/protocols/operations
In MSDN, Microsoft also mentions this about using REST in conjunction with SharePoint 2010's WCF based REST API:
msdn.microsoft.com/en-us/library/ff798339.aspx
"In practice, many firewalls and other network intermediaries block HTTP verbs other than GET and POST. To work around this issue, WCF Data Services (and the OData standard) support a technique known as "verb tunneling." In this technique, PUT, DELETE, and MERGE requests are submitted as a POST request, and an X-HTTP-Method header specifies the actual verb that the recipient should apply to the request. For more information, see X-HTTP-Method on MSDN and OData: Operations (the Method Tunneling through POST section) on the OData Web site."
Don Box's also had some words about this, but regarding GData specifically:
www.pluralsight-training.net/community/blogs/dbox/archive/2007/01/16/45725.aspx
"If I were building a GData client, I honestly wonder why I'd bother using DELETE and PUT methods at all given that X-HTTP-Method-Override is going to work in more cases/deployments."
There's an article about Silverlight and Java interop which also addresses this limitation of Silverlight by giving the same advice:
www.infoq.com/articles/silverlight-java-interop
"Silverlight supports only the GET and POST HTTP methods. Some firewalls restrict the use of PUT and DELETE HTTP methods.
It is important to point out that true RESTful service can be created (conforming to all the REST principles listed above) only using the GET and POST HTTP methods, in other words the REST architecture does not require a specific mapping to HTTP. Google’s GData X-Http-Method-Override header is an example of this approach.
The following HTTP methods overrides may be set in the header to accomplish the PUT and DELETE actions if the web services interpret the X-HTTP-Method-Override header on a POST:
* X-HTTP-Method-Override: PUT
* X-HTTP-Method-Override: DELETE"
Hope this helps
-Josh
It depends on whether you're using the browser HTTP stack or the client HTTP stack. The client stack does not support client certificates, period. The browser stack does, and pretty much automatically, if you're willing to live with its other limitations (lack of support for all HTTP verbs, coercion of response status codes, etc.).
I have however been running into a problem using the browser stack with client certificates in an OOB scenario. Prism module loading fails under these conditions - the request gets to IIS, but causes a 500 server error for no apparent reason. If I set IIS to ignore client certs, or if I run the app in-browser, it works fine :-/
take a look at this.
http://support.microsoft.com/kb/307267
just change your urls to https
hope this helps
Dim url As Uri = New Uri(Application.Current.Host.Source, "../WebService.asmx")
Dim binding As New System.ServiceModel.BasicHttpBinding
If url.Scheme = "https" Then
binding.Security.Mode = ServiceModel.BasicHttpSecurityMode.Transport
End If
binding.MaxBufferSize = 2147483647 'this value set to override a bug,
binding.MaxReceivedMessageSize = 2147483647 'this value set to override a bug,
Dim proxy As New ServiceReference1.WebServiceSoapClient(binding, New ServiceModel.EndpointAddress(url))
proxy.InnerChannel.OperationTimeout = New TimeSpan(0, 10, 0)
I'm having an issue where IIS 7.5 (on Windows 7 64-bit) is failing when I call it from an out-of-browser Silverlight 4 app using SSL and a client certificate, with the message "The I/O operation has been aborted because of either a thread exit or an application request. (0x800703e3)". The request does make it to IIS. here is a sample from the failed request trace:
The I/O operation has been aborted because of either a thread exit or an application request. (0x800703e3) http://www.slipjig.org/IISError.gif
I am using the browser HTTP stack, because the client HTTP stack does not support client certificates. The client code attempting to hit the server is the Prism module loader. If I run the app out-of-browser but ignore client certs, or if I run the application in-browser but require client certs, it works fine. It seems to be the combination of the two that is causing the problem.
I tried the following to gather more info:
Used Fiddler to view the failing request. It works if Fiddler is running (presumably because Fiddler is handling the client certificate differently?);
Created an .aspx web form to serve up the module .xaps;
Created an HTTPModule to see if I could intercept the request before it failed;
Used a packet sniffer to see if I could tell if the client certificate was being sent correctly.
None of the above gave me much useful information beyond what I could see in the trace file, although the Fiddler thing is interesting.
Any ideas? Thanks in advance!
Mike
I beat my head against the wall for weeks on this problem. Here's what I learned and how I finally worked around it.
Prism's FileDownloader class uses System.Net.WebClient to load modules. In OOB mode, WebClient seems to use the same stack as IE, but it apparently either doesn't send the client certificate, or (more likely) doesn't correctly negotiate the SSL/client cert handshake with the server. I say this because:
I was able to successfully request .xap files using Firefox and Chrome;
I was not able to successfully request .xap files using IE;
IIS would fail with a 500, not a 403.
I couldn't get good visibility into what was actually happening over the wire; if I used Fiddler, it would work, because Fiddler intercepts communications with the server and handles the client certificate handshake itself. And trying to use a packet sniffer obviously wouldn't tell me anything because of SSL.
So - I first spent a lot of time on the server side trying to eliminate things (unneeded handlers, modules, features, etc.) that might be causing the problem.
When that didn't work, I tried modifying the Prism source code to use the browser's HTTP stack instead of WebClient. To do this, I created a new class similar in design to FileDownloader, implementing IFileDownloader, that used the browser stack. I then made some changes to XapModuleTypeLoader (which instantiates the downloader) to make it use the new class. This approach failed with the same error I was originally experiencing.
Then I started researching whether a commercial third-party HTTP stack might be available. I found one that supported the features I needed and that supported the Silverlight 4 runtime. I created another implementation of IFileDownloader that used that stack, and BOOM - it worked.
The good news with this approach is that not only can I use this to load modules, I can also use it to protect communications between the client and our REST API (a benefit we were going to give up, before).
I plan to submit a patch to Prism to allow the downloader to be registered or bound externally, as it's currently hard-coded to use its own FileDownloader. If anyone is interested in that or in the commercial HTTP stack I'm using, contact me (msimpson -at- abelsolutions -dot- com) for links and code samples.
And I must say this - I still don't know for sure whether the root problem is in the HTTP stack on the client side or the server side, but it's a FAIL on Microsoft's part nonetheless.
What we (Slipjig and I) found out this week is that there does appear to be a way around these issues, or at least, we're on the trail to determining whether there is a reliable, repeatable way. We're still not positive on that, but here's what we know so far:
At first pass, if you have code like this you can start making requests with either the Browser or Client stack:
First, place a "WebBrowser" control in your Silverlight XAML, and make it send a request to your HTTPS site.
This may pop up the certificate dialog box for the user. Big deal. Accept it. If you have only one cert, then you can turn an option in IE off to suppress that message.
private void Command_Click(object sender, RoutedEventArgs e) {
// This does not pop up the cert dialog if the option to take the first is turned on in IE settings:
BrowserInstance.Navigate(new Uri("https://www.SiteThatRequiresClientCertificates.com/"));
}
Then, in a separate handler invoke by the user, create an instance of your stack, either Client or Browser:
private void CallServer_Click(object sender, RoutedEventArgs e) {
// Works with BrowserHttp factory also:
var req = WebRequestCreator.ClientHttp.Create(new Uri("https://www.SiteThatRequiresClientCertificates.com/"));
req.Method = "GET";
req.BeginGetResponse(new AsyncCallback(Callback), req);
}
Finally, the Callback:
private void Callback(IAsyncResult result)
{
var req = result.AsyncState as System.Net.WebRequest;
var resp = req.EndGetResponse(result);
var content = string.Empty;
using (var reader = new StreamReader(resp.GetResponseStream())) {
content = reader.ReadToEnd();
}
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
{
Results.Text = content;
});
}
I had the same issue and I fixed it by creating the certificate using makecert. Follow the steps from this article http://www.codeproject.com/Articles/24027/SSL-with-Self-hosted-WCF-Service and replace CN with your ip/domain. In my case I have tested the service on the local machine and run the commands as follows:
1) makecert -sv SignRoot.pvk -cy authority -r signroot.cer -a sha1 -n "CN=Dev Certification Authority" -ss my -sr localmachine
after running the first command drag the certificate from "Personal" directory to "Trusted Root Certification Authority"
2) makecert -iv SignRoot.pvk -ic signroot.cer -cy end -pe -n
CN="localhost" -eku 1.3.6.1.5.5.7.3.1 -ss my -sr
localmachine -sky exchange -sp
"Microsoft RSA SChannel Cryptographic Provider" -sy 12
In case you want to run the silverlight application on another machine, export the certificate created at step1 and then import it on any machine where you want your application to run.