I'm writing a secure WCF REST webservice using C#.
My code is something like this:
public class MyServiceAuthorizationManager : ServiceAuthorizationManager
{
protected override bool CheckAccessCore(OperationContext operationContext)
{
base.CheckAccessCore(operationContext);
var ctx = WebOperationContext.Current;
var apikey = ctx.IncomingRequest.Headers[HttpRequestHeader.Authorization];
var hash = ctx.IncomingRequest.Headers["Hash"];
var datetime = ctx.IncomingRequest.Headers["DateTime"];
...
I use headers (Authorization,Hash,DateTime) to store informations about apikey, current datetime and the hashed request URL while request body contains only URL and webservice parameters.
Example:
http://127.0.0.1:8081/helloto/daniele
Is this the right way or I've to pass and retieve those parameters from URL like this:
http://127.0.0.1:8081/helloto/daniele&apikey=123&datetime=20120101&hash=ddjhgf764653ydhgdhgfjiutu56
are there differences between those two methods?
I think both methods would work for simple cases. However, if you want to make maximum use of native HTTP behaviours, you should go with the headers approach, not the URL query parameters one.
This will allow you to (for example) use HTTP response codes to indicate to client that a resource has been permanently moved (response code 301) so the client can automatically update links. If the URL included the authentication information, it is not clear to a client that two different URLs are actually referring to the same resource. In other redirect scenarios, the headers will be automatically included so you don't have to worry about appending parameters to redirect URLs.
Also, it should allow better caching behaviour on clients (if that is relevant in your scenario).
As another example, using headers would allow you to authenticate a request based just on the headers without requiring the client to send the message body. The idea is that you authenticate with the headers, then send the client an HTTP 100 Continue response. The client should not send the message body until it gets the 100. This could be an important optimisation if you are doing POSTs or PUTs with large message bodies.
There are other examples, but whether any given one is relevant depends on your scenarios and on the clients you expect to serve.
In summary, I would say it is better to make use of elements of the protocol as they were explicitly intended - this gives you the best chance of behaving as a client expects and should make your service more accessible, efficient and usable in the longer term.
Based on your implementation, your required parameters would have to be passed in the HTTP Headers of the request, which would most certainly not be on the query string.
Related
I am trying to add a custom header to google bigquery client in below way, some reasons it is not working. Can someone suggest me how I can add custom header to google bigquery client.
Below is my sample code:
var gClient = BigQueryClient.Create(projectId, credential);
gClient.Service.HttpClient.DefaultRequestHeaders.TryAddWithoutValidation("test", "this is default header");
var results = gClient.ExecuteQuery(query, null);
With above code, I can see that the custom header 'test' is added to the httpclient, but when gClient executes the query, I don't see this custom header.
I am using the fiddler to monitor the traffic from my machine. In fiddler, the I can see that there are two calls are made.
i. oauth authentication
ii. bigquery execution
In both of the messages I dont see the default http header 'test'.
I also tried, gClient.Service.HttpClientInitializer.Initialize() to initialize the httpclient, but didnt work.
var gClient = BigQueryClient.Create(projectId, credential);
ConfigurableHttpClient httpClient = new ConfigurableHttpClient(new ConfigurableMessageHandler(new CustomMessageHandler()), true);
httpClient.DefaultRequestHeaders.Add("xxxxx", "yyyyyyy");
gClient.Service.HttpClientInitializer.Initialize(httpClient);
In this case also, it is same problem... the default header is not part of the httprequest.
Can someone help me to solve this issue...?
FYI... we are intercepting all outbound calls using a proxy and based on this custom http header we need to take decision whether to allow outbound call or not. So, we would like to inject it at the service side and verify this custom header in the proxy.
As explained above, I have tried adding the DefaultRequestHeaders to the httpclient, but it is not working.
Also, I have tried httpclient.MessageHandler.AddExecuteInterceptor(). but still didnt work.
My question... can we inject a default httpclient for all outbound calls in c#? especially for google big queries.
I have a web application which is a mesh of a few different servers and 1 server is the front-end server which handles all request external incoming requests.
So some of these request will have to be passed along to different servers and ideally the only thing I want to change is the host and Uri fields of these request. Is there a way to map an entire incoming request to a new outgoing request and just change a few fields?
I tried something like this:
// some controller
public HttpResponseMessage get()
{
return this.Request.Rewrite("192.168.10.13/api/action");
}
//extension method Rewrite
public static HttpResponseMessage Rewrite(this HttpRequestMessage requestIn, string Uri) {
HttpClient httpClient = new HttpClient(new HttpClientHandler());
HttpRequestMessage requestOut = new HttpRequestMessage(requestIn.Method, Uri);
requestOut.Content = requestIn.Content;
var headerCollection = requestIn.Headers.ToDictionary(x => x.Key, y => y.Value);
foreach (var i in headerCollection)
{
requestOut.Headers.Add(i.Key, i.Value);
}
return httpClient.SendAsync(requestOut).Result;
}
The issue I am having is that this has a whole slew of issues. If the request is a get Content shouldn't be set. THe headers are incorrect since it also copies things like host which shouldn't be touched afterwards etc.
Is there an easier way to do something like this?
I had to do this in C# code for a Silverlight solution once. It was not pretty.
What you're wanting is called reverse proxying and application request routing.
First, reverse proxy solutions... they're relatively simple.
Here's Scott Forsyth and Carlos Aguilar Mares guides for creating a reverse proxy using web.config under IIS.
Here's a module some dude named Paul Johnston wrote if you don't like the normal solution. All of these focus on IIS.
Non-IIS reverse proxies are more common for load balancing. Typically they're Apache based or proprietary hardware. They vary from free to expensive as balls. Forgive the slang.
To maintain consistency for the client's perspective you may need more than just a reverse proxy configuration. So before you go down the pure reverse proxy route... there's some considerations.
The servers likely need to share Machine Keys to synchronize view state and other stuff, and share the Session Store too.
If that's not consistent enough, you may want to implement session stickiness through Application Request Routing (look for Server Affinity), such that a given session cookie (or IP address, or maybe have it generate a token cookie) maps the user to the same server on every request.
I also wrote a simple but powerful reverse proxy for asp.net / web api. It does exactly what you need.
You can find it here:
https://github.com/SharpTools/SharpReverseProxy
Just add to your project via nuget and you're good to go. You can even modify on the fly the request, the response, or deny a forwarding due to authentication failure.
Take a look at the source code, it's really easy to implement :)
I'm writing a simple REST client for a C# WinForm application. I use RestSharp to make sending requests and getting responses easier. I have a few questions regarding how I should design my client.
The user interacts with the client only once. He pushes a Button and the client is instantiated and passed to private methods to do some logic in the background. It accesses objects from the server and synchronizes them with objects in the user's internal database.
The point is that the client's methods are accessed by private methods called following the user's single action in the GUI. He does not have any control over which of the client's methods are called, and in which order.
So my questions are:
Can I ask the server for a token only once when I instantiate my client, and then store it in the client instance for future reference in the client's following requests? The token is a hash of the username and password, so it should not change over time. Of course, once I create a new instance of the client, it will again ask the server for a token.
Is it okay to keep a single Request object instance in my client? I can then set request header only once and all the methods that access the API will only need to change the request's resource URL and HTTP method. It would reduce repetitiveness in my code.
For example:
public PriceListItem[] GetPriceListItems()
{
string requestUrl = Resources.PriceListItemsUrl;
var request = new RestRequest(requestUrl, Method.GET);
request.AddHeader("SecureToken", _token);
var response = Client.Execute(request) as RestResponse;
JObject jObject = JObject.Parse(response.Content);
var priceListItems = jObject["Data"].ToObject<PriceListItem[]>();
return priceListItems;
}
I have quite a few methods for utilizing different resource URLs, but all have the same header. If I keep only one Request instance in my client I can set the header only once. Is this approach okay? I would like to avoid any delegates and events.
You have to use ParameterType.HttpHeader parameter:
request.AddParameter("Authorization", "data", ParameterType.HttpHeader);
It's perfectly normal to save auth token on client, as long it's encrypted and have expired time on it.
You can improve it with implement session on your REST API, so you just need check if the auth token is still valid or not, and do the authentication if it's not valid.
Clearly you need to manage the way you request to the REST API, I Recommend you to use IDisposable Pattern for this manner, you can utilize some lazy implementation or Singelton.
I've got an .ashx handler which, upon finishing processing will redirect to a success or error page, based on how the processing went. The handler is in my site, but the success or error pages might not be (this is something the user can configure).
Is there any way that I can pass the error details to the error page without putting it in the query string?
I've tried:
Adding a custom header that contains the error details, but since I'm using a Response.Redirect, the headers get cleared
Using Server.Transfer, instead of Response.Redirect, but this will not work for URLs not in my site
I know that I can pass data in the query string, but in some cases the data I need to pass might be too long for the query string. Do I have any other options?
Essentially, no. The only way to pass additional data in a GET request (i.e. a redirect) is to pass it in the query string.
The important thing to realise is that this is not a limitation of WebForms, this is just how HTTP works. If you're redirecting to another page that's outside of your site (and thus don't have the option of cookies/session data), you're going to have to send information directly in the request and that means using a query string.
Things like Server.Transfer and Response.Redirect are just abstractions over a simple HTTP request; no framework feature can defy how HTTP actually works.
You do, of course, have all kinds of options as to what you pass in the query string, but you're going to have to pass something. If you really want to shorten the URL, maybe you can pass an error code and expose an API that will let the receiving page fetch further information:
Store transaction information (or detailed error messages) in a database with an ID.
Pass the ID in the query string.
Expose a web method or similar API to allow the receiving page to request additional information.
There are plenty of hacky ways you could create the illusion of passing data in a redirect outside of a form post (such as returning a page containing a form and Javascript to immediately do a cross-domain form post) but the query string is the proper way of passing data in a GET request, so why try to hack around it?
If you must perform a redirect, you will need to pass some kind of information in the Query String, because that's how browser redirects work. You can be creative about how you pass it, though.
You could pass an error code, and have the consuming system know what various error codes mean.
You could pass a token, and have the consuming system know how to ask your system about the error information for the given token behind-the-scenes.
Also, if you have any flexibility around whether it's actually performing a redirect, you could use an AJAX request in the first place, and send back some kind of JSON object that the browser's javascript could interpret and send via a POST parameter or something like that.
A redirect is executed by most browsers as a GET, which means you'd have to put the data in the query string.
One trick (posted in two other answers) to do a "redirect" as a POST is to turn the response into a form that POSTs itself to the target site:
Response.Clear();
StringBuilder sb = new StringBuilder();
sb.Append("<html>");
sb.AppendFormat(#"<body onload='document.forms[""form""].submit()'>");
sb.AppendFormat("<form name='form' action='{0}' method='post'>",postbackUrl);
<!-- POST values go here -->
sb.AppendFormat("<input type='hidden' name='id' value='{0}'>", id);
sb.Append("</form>");
sb.Append("</body>");
sb.Append("</html>");
Response.Write(sb.ToString());
Response.End();
But I would read the comments on both to understand the limitations.
Basically there are two usual HTTP ways to send some data - GET and POST.
When you redirect to another URL with additional parameters, you make the client browser to send the GET request to the target server. Technically, your server responds to the browser with specific HTTP error code 307 + the URL to go (including the GET parameters).
Alternatively, you may want/need to make a POST request to the target URL. In that case you should respond with a simple HTML form, which consists of several hidden fields pre-filled with certain values. The form's action should point the target URL, method should be "POST", and of course your HTML should include javascript, which automatically submits the form once the document is loaded. This way the client browser would send the POST request instead of the GET one.
I'm trying to get the raw data sent to IIS using a HttpHandler. However, because the request is an "GET"-request without the "Content-Length" header set it reports that there is no data to read (TotalBytes), and the inputstream is empty. Is there any way I can plug into the IIS-pipeline (maybe even before the request is parsed) and just kind of take control over the request and read it's raw data? I don't care if I need to parse headers and stuff like that myself, I just want to get my hands on the actual request and tell IIS to ignore this one. Is that at all possible? Cause right now it looks like I need to do the alternative, which is developing a custom standalone server, and I really don't want to do that.
Most web servers will ignore (and rarely give you access to) the body of a GET request, because the HTTP semantics imply that it is to be ignored anyway. You should consider another method (for example POST or PUT).
See this question and the link in this answer:
HTTP GET with request body