C# calling a API endpoint with CSRF token its not working - c#

I need to develop a .NET Job that triggers an execution in the HPOO software, by calling API endpoint that requires a CSRF token.
Before I started coding, I tested the scenario in Postman:
calling a normal GET endpoint only with the basic authentication
getting back a CSRF token
and then finally calling a POST API, passing the basic authentication together with the CSRF token.
Everything worked as expected when I did these tests in Postman.
When I try to implement the same scenario in code, the program blocks when calling the POST endpoint (passing the token).
Follow my code below:
ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
var uriExecution = new Uri("https://hpoo-api.com.br/oo/rest/v2/executions");
var cookies = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriExecution);
request.Method = "GET";
request.ContentType = "application/json; charset=utf-8";
request.Headers.Add("Authorization", "Basic " + GetBasicAuthenticaton());
request.CookieContainer = cookies;
var response = request.GetResponse();
var csrf = response.Headers.Get("X-CSRF-TOKEN");
HttpWebRequest request2 = (HttpWebRequest)WebRequest.Create(uriExecution);
request2.Method = "POST";
request.ContentType = "application/json; charset=utf-8";
request.Accept = "application/json";
request2.Headers.Add("Authorization", "Basic " + GetBasicAuthenticaton());
request2.Headers.Add("X-CSRF-TOKEN", csrf);
request2.CookieContainer = cookies;
var response2 = request2.GetResponse();
At the moment my code calls the method GetResponse() of request2, I get a exception saying I'm forbidden to access (403).
I tried with HttpClient library too, but I got the same error, specifying that I'm forgetting the CSRF token.
Some things that I already tried which have not worked:
Created a new CookieContainer, with all cookies in the first request, and pass to the request2.
Removed the CSRF header, only cookies.
Removed the cookies, only passing the header.
Removed the CSRF header, only passing the CSRF query and cookies.
Removed basic authentication, only passing the CSRF header and cookies.
Please, someone could help me?
Sorry for my bad english, brazilian here...

I found out the problem. Even colleting the cookies from first request and storing in a CookieContainer, the second request wasn't sending the cookies. After some search, I see its possible to send cookies in header, like this:
request.Headers.Add("Cookie", "cookie1=value1; cookie2=value2");
This way works like a charm, I only have to understand why using CookieContainer doesn't work...

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.

How to understand the difference between Windows/.NET and Linux/Mono with a .NET WebRequest and a PFX certificate?

I'm currently working with an API that uses client certificate authentication. And I have a simple block of code that works under Linux/Mono. When executing under Windows/.NET, I receive a 200, but the response content hints that I need a certificate to make this call.
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
var x509 = new X509Certificate2("foo.pfx", "test");
var request = (HttpWebRequest)WebRequest.Create("https://domain.com:8081");
request.Method = "POST";
request.ClientCertificates.Add(x509);
const string data = "{\"foo\":\"bar\"}";
var postdata = Encoding.ASCII.GetBytes(data);
request.ContentLength = data.Length;
var myStream = request.GetRequestStream();
myStream.Write(postdata, 0, postdata.Length);
var response = (HttpWebResponse)request.GetResponse();
Console.WriteLine(new StreamReader(response.GetResponseStream()).ReadToEnd());
The same foo.pfx is used in both cases. Does anyone know how I can explain the difference in results?
Is there some redirection ?
If yes, MSDN says:
The Authorization header is cleared on auto-redirects and HttpWebRequest automatically tries to re-authenticate to the redirected location. In practice, this means that an application can't put custom authentication information into the Authorization header if it is possible to encounter redirection. Instead, the application must implement and register a custom authentication module. The System.Net.AuthenticationManager and related class are used to implement a custom authentication module. The AuthenticationManager.Register method registers a custom authentication module.

Twitter authorized / signed get request returing 401 not authorized

I'm trying to make an authorized get request to api.twitter.com/1/followers/ids.xml It keeps returning 401 not authorized. .Ive checked the header and base string against the ones generated in the OAuth tool in twitter developers app page and they are exactly the same. I've also tried changing the method to post instead of get to no avail.
here is the code:
ServicePointManager.Expect100Continue = false;
HttpWebRequest request =(HttpWebRequest)WebRequest.Create("http://api.twitter.com/1/followers/ids.xml");
request.Headers.Add(Uri.EscapeDataString("Authorization: "), authHeader);
request.Method = "GET";
request.ContentType = "application/x-www-form-urlencoded";
WebResponse response = request.GetResponse();
Is there a problem with the way I am sending the request?
You need to add either the screen_name or user_id of the twitter user you're interested in. For example: https://api.twitter.com/1/followers/ids.json?cursor=-1&screen_name=twitterapi

Get the .ASPXAUTH cookie value programmatically

Is there a way to get the .ASPXAUTH value programmatically.
Example I login to a website with my own credentials (POST) and then read the response...it does not return the .APSXAUTH in the CookieContainer that I use to track the session.
Anyone has a clue how can I get it and send it with the subsequent gets and posts?
[EDIT] Here's what I do to be more specific:
send a HTTP GET to a page. read values like _VIEWSTATE etc.
send a HTTP POST to the Login page. It includes the login information.
The server sends a 302 response (redirect) to some Default page. The forms authentication cookie is supposed to be included but it's not.
So I was thinking that there might be a better way than this to track session:
CookieContainer _cookieJar = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_url);
request.CookieContainer = _cookieJar;
So the summarize the answer:
If you're trying to login programatically on a Forms based authentication website trough your own application make sure you follow the steps you take that track the cookies.
First create a initial GET request, and then do the subsequential POST requests that will do the postback.The request and the responses should be formulated in this way:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_url);
request.CookieContainer = _cookieJar;
HttpWebResponse httpsResponse = (HttpWebResponse)request.GetResponse();
The CookieContainer class handles the cookies as expected.
And if your response is encoded with Gzip just include the following line:
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
before you call request.GetResponse()
Hope this helps someone out there.

Automatic Cookie Handling C#/.NET HttpWebRequest+HttpWebResponse

Is there any way to automatically handle cookies in .NET with the HttpWebRequest/HttpWebResponse objects? I'm preferably looking for an equivalent to LWP::UserAgent and its behaviour (perl), only in a .NET environment.
Any suggestions or advice?
I think what you're looking for is the CookieContainer class. If I understand what you're trying to do correctly, you have separate objects for request & response, and you want to transfer the response cookie collection into the next request cookie collection automatically. Try using this code:
CookieContainer cookieJar = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://www.google.com");
request.CookieContainer = cookieJar;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
int cookieCount = cookieJar.Count;
Once you create a cookieJar and set it to the request's CookieContainer, it will store any cookies that come from the response, so in the example above, the cookie jar's count will be 1 once it visits Google.com. The cookie container properties of the request & response above will store a pointer to the cookieJar, so the cookies are automatically handled and shared between the objects.

Categories