c# HttpWebRequest.GetRequestStream Authorization - c#

I got a web Api Controller which is flagged with the Authorize tag.
https://msdn.microsoft.com/de-de/library/system.web.http.authorizeattribute(v=vs.118).aspx
[Authorize()]
public class SomeController : ApiController {}
I'm using HttpWebRequest to do a Post-Request to that controller as follows:
(Please note, I do not provide an authorization header in order to show my issue)
var httpWebRequest = (HttpWebRequest)WebRequest.Create("SomeUrl");
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "POST";
StreamWriter streamWriter;
// 1) no error here, works without authentication
using (streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = "{\"Message\":\"Test\"," + "\"Data\":\"\"}";
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
// 2) here I get a 401: not authorized
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
Problem:
I expected to get a not authorized exception, when asking for the request stream. But I can call GetRequestStream and even write to that stream, without any issue.
Only when GetRespone is called, I get the 401 (Not Authorized) which I expected earlier.
I'm just wondering, if this is intended behaviour? And If there is any way to change that. For example, if I want to upload a huge file, all the data will be uploaded before the client is informed that it is not authorized to do so. Somehow that does not make sense to me? Or do I miss something?

You are right, ideally, the GetRequestStream() call should have resulted in the request being sent to the server, and the server responding with a 401.
I think what might be happening is that the server is waiting for you to post the data before replying with the final status. THat is why you get the final response when you call request.GetResponse()
In any case, you should handle exceptions and do the needful.

Related

Stripe 401 - No valid API key provided - C#

I get following error: "The remote server returned an error: (401) Unauthorized" in this line:
using (HttpWebResponse httpResponse = request.GetResponse() as HttpWebResponse) {}
Here is the complete code:
string clientSecretKey = ConfigurationManager.AppSettings["ClientSecretKey"];
const string ChargeUrl = "https://api.stripe.com/v1/charges?amount={0}&currency={1}&source={2}&description={3}";
string requestUrl = HttpUtility.UrlPathEncode(
String.Format(ChargeUrl, 1000, "usd", "tok_19xLu8HN9aKw9vrkUsflNWOI", "Test charge to text#example.com") );
HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest;
request.Headers.Add("Authorization", "sk_test_example");
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
using (HttpWebResponse httpResponse = request.GetResponse() as HttpWebResponse)
{/* some code */}
At the beginning I thought the error was caused because the token can't used more than one time, but I changed it and got the same error. I'm not sure what is causing the error.
The issue here is that you are passing the API key but not using Bearer authentication which is what Stripe's API expects. You need to change your Authorization header like this:
request.Headers.Add("Authorization", "Bearer sk_test_example");
I know you mentioned in the comments that you can't use a third-party library but I wanted to mention one just in case. Stripe.net lets you use Stripe's API in .Net easily without having to rewrite the logic yourself. Handling errors, encoding parameters and sub-hashes properly, managing authentication and JSON decoding, all of this will take a lot of time and trial and error to build from scratch while this library would handle all of this for you.
You're initializing a variable for the secret key but not using it. Try modifying the request url to start with "https://" + clientSecretKey + ":#api..."
This is, of course, assuming clientSecretKey is the Stripe key.
Be careful putting a secret key somewhere on your server that it isn't hidden from a user / client.

Authentication to REST API: digest type with cookie (c#)

I have a service REST API where I tryied to connect.
Using browser all is ok.
But in c# I always have an unauthorized answer.
I investigated this issue using fiddler and find out that in first unsuccessful reuest server returns some cookie, and browser use it in next session together with username/password (digest type).In this case second session is successful.
But when I try to send request using c# (I tried work with System.Net.WebClient and HttpWebRequest) I don't get response (I had timeout exception after some time).
My code:
WebClient webClient = new WebClient();
CredentialCache cache = new CredentialCache();
Uri prefix = new Uri(Url);
cache.Add(prefix, "Digest", new NetworkCredential(login, password));
webClient.Credentials = cache;
...
string response = webClient.DownloadString(restRequest);
Last line throws exception.
When I investigated this issue in Fiddler I found out that in first session with status 401 we recieved cookie (like on picture below).
fiddler's picture
Browser sends this cookie in next request and authentication happens successfully.
But in c# I couldn't geet this response with status 401. As I see in fiddler studio try to open new session 10-20 times during each next seconds before timeout exception will be thrown. And my response in null.
Also I have other environment without required cookie, there my code is working.
Please, give me a piece of advise hoe to get response with Status 401 and get cookie from it to set it to another request.
thanks
Mike
I resolved this issue using HttpWebRequest with defined empty (not null) CookieContainer.
My code:
HttpWebRequest request1;
HttpWebResponse response1 = null;
String responseBody;
request1 = (HttpWebRequest) WebRequest.Create(requestString);
request1.Credentials = cache;
request1.CookieContainer = new CookieContainer();
response1 = (HttpWebResponse) request1.GetResponse();
using (StreamReader stream = new StreamReader(response1.GetResponseStream(), Encoding.UTF8))
{
responseBody = stream.ReadToEnd();
}
In this implementation after first session with status 401 requests provide cookie from first session to next one and it returns with status code 200 OK.

Changing HTTP Request to HTTPS, message content seems to be lost

This is not a subject I am strong in so I apologize ahead of time if I say something ridiculous.
I have developed an HTTP service using Mule. I have it functioning perfectly when I connect directly to the service and send data using a test harness I wrote in C#.
As the final part of my testing, I need to send it to an HTTPS URL that is supposed to "decrypt" the message and forward it to my service. When I send a message to the HTTPS URL, it gets forwarded to my service but the message contents appear empty and therefore does not get processed. I understand that I may have to add some "encryption" to my Test Harness but I have been researching how to do this all day and nothing I have found is answering my question.
Here is an example of the code I am using for the simple HTTP request:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(ConfigurationManager.AppSettings["HttpDestination"].ToString());
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = data.Length;
using (Stream strm = req.GetRequestStream())
{
strm.Write(data, 0, data.Length);
}
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
What do I need to change here to make this work?
Here is the solution that I discovered here. I needed to add the following line:
req.ProtocolVersion = System.Net.HttpVersion.Version10;
Without this, a timeout was occurring when getting the request stream and the content was never being sent, only the headers.

Getting headers from WebRequest

Technically I'm asking a question for a friend who writes VB, but I post as C# since more people are on it. And I personally know neither.
I'm helping him connecting to a Mobile Backend as a Service, although the way he set up he is connecting it on behalf of someone loading his own web page with ASP.net (I think).
I'm connecting to the service just fine using Python. But he is getting a 422 server response. I would like to compare the request header & content difference between his and mine.
According to Chris Doggett's post on this page down below, you can't get the headers until the request is actually sent. However, as soon as request.GetResponse() is called, Visual Studio (or the Express, not sure) seems to just halt on a break point there and say there is a 422 error and some error message on the browser. So, he can't get to the next line where he wish to print out the headers.
Two questions:
Is that some sort of debugging turned on? I thought a 422 response is a response nevertheless and the program shouldn't just stop there.
How do I print out the the content as well, not just the headers? Preferably, I want to print out the entire request in text. There is this stuff sent in JSON and I don't think that belongs to the headers but I'm not so sure.
The Create method will return an HttpWebRequest for an http/https url. The 422 status code indicates that you are somehow sending incorrect formed data to the server. GetResponse() will throw a WebException because you don't receive the
status code 200.
To get the actual headers of the response you need to handle the exception
private static void Main(string[] args)
{
WebRequest request = WebRequest.Create("http://google.com/12345"); //generate 404
try
{
WebResponse response = request.GetResponse();
}
catch(WebException ex)
{
HttpWebResponse errorResponse = ex.Response as HttpWebResponse;
if (errorResponse == null)
throw; //errorResponse not of type HttpWebResponse
string responseContent = "";
using(StreamReader r = new StreamReader(errorResponse.GetResponseStream()))
{
responseContent = r.ReadToEnd();
}
Console.WriteLine("The server at {0} returned {1}", errorResponse.ResponseUri, errorResponse.StatusCode);
Console.WriteLine("With headers:");
foreach(string key in errorResponse.Headers.AllKeys)
{
Console.WriteLine("\t{0}:{1}", key, errorResponse.Headers[key]);
}
Console.WriteLine(responseContent);
}
Console.ReadLine();
}

Can I send an empty HTTP POST WebRequest object from C# to IIS?

Do I need to just slap some random garbage data in a WebRequest object to get by the HTTP status code 411 restriction on IIS?
I have an HttpPost action method in an MVC 3 app that consumes a POST request with all the relevant information passed in the querystring (no body needed).
[HttpPost] public ActionResult SignUp(string email) { ... }
It worked great from Visual Studio's built in web host, Cassini. Unfortunately, once the MVC code was live on IIS [7.5 on 2008 R2], the server is pitching back an HTTP error code when I hit it from my outside C# form app.
The remote server returned an error:
(411) Length Required.
Here is the calling code:
WebRequest request = WebRequest.Create("http://somewhere.com/signup/?email=a#b.com");
request.Method = "POST";
using (WebResponse response = request.GetResponse())
using (Stream responseStream = response.GetResponseStream())
using (StreamReader responseReader = new StreamReader(responseStream)) {
// Do something with responseReader.ReadToEnd();
}
Turns out you can get this to go through by simply slapping an empty content length on the request before you send it.
WebRequest request = WebRequest.Create("http://somewhere.com/signup/?email=a#b.com");
request.Method = "POST";
request.ContentLength = 0;
Not sure how explicitly giving an empty length vs. implying one makes a difference, but IIS was happy after I did. There are probably other ways around this, but this seems simple enough.
I believe you are required to set a Content-Length header anytime you post a request to a web server:
http://msdn.microsoft.com/en-us/library/system.web.httprequest.contentlength.aspx
You could try a GET request to test it.

Categories