c# httpwebrequest for basic authentication - c#

I've been trying to use a username, password and access key to authenticate on a server, so that I could use its API. I used to following code:
string encoded = Convert.ToBase64String(Encoding.Default.GetBytes("myusername:mypass"));
string api = "blahblahblahblabh";
string auth_string = "Basic " + encoded;
string _post_string = "username=myusername&password=mypass&grant_type=password";
HttpWebRequest request = WebRequest.Create(https_website) as HttpWebRequest;
request.Accept = "application/xml";
request.Method = "POST";
request.ContentType = "application/x-www-forms-urlencoded";
request.ContentLength = _post_string.Length;
CookieContainer cookies = new CookieContainer();
request.CookieContainer = cookies;
request.Headers["Authorization"] = auth_string;
request.Headers["api-key"] = api;
request.ServerCertificateValidationCallback += (sender1, certificate, chain, sslPolicyErrors) => { return true; };
StreamWriter writer = new StreamWriter(request.GetRequestStream());
writer.Write(_post_string);
writer.Close();
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
StreamReader reader = new StreamReader(response.GetResponseStream());
string xml_response = reader.ReadToEnd();
reader.Close();
So I sent a POST request with the username/password and access_key and tried to receive a response. I always get "The remote server returned an error: (404) Not Found". If I add more to the string of the 1st line, for example if instead of "myusername:mypass" I use "myusername:mypass:password" I get an error 401 (Unauthorized). I don't understand why this is happening...

Related

C# WebRequest - HTTP: 403 Forbidden ('_xsrf' argument missing from POST)

I'm stucked here at getting a WebResponse from HTTPWebRequest.
The WebRequest.GetResponse() Method throws a WebException
("500 Internal Server Error"). When i read the returned HTML it says:
HTTP 403: Forbidden ('_xsrf' argument missing from POST)
Anyone knows this Error or knows what Im doing wrong?
(Im trying to log in to a Website using POST)
EDIT:
My sourcecode:
private String GetLoginCookies(String pHTTPurl, String pUserIDwithFormID, String pPasswordWithFormID)
{
String loginPageUrl = pHTTPurl;
CookieContainer cookieContainer = new CookieContainer();
var Request = (HttpWebRequest)WebRequest.Create(loginPageUrl);
Request.CookieContainer = cookieContainer;
Request.Method = "GET";
WebResponse Response = Request.GetResponse();
HttpWebResponse HttpResponse = Response as HttpWebResponse;
CookieCollection cookies = null;
if (HttpResponse != null)
{
//Cookies die benötigt werden um den Loginvorgang abzuschließen
cookies = HttpResponse.Cookies;
}
string formParams = string.Format(pUserIDwithFormID + "&" + pPasswordWithFormID);
Request = (HttpWebRequest)WebRequest.Create(loginPageUrl);
Request.CookieContainer = cookieContainer;
Request.UserAgent = "I am not a Bot! Ok maybe..";
WebResponse resp = null;
Request.ContentType = "application/x-www-form-urlencoded";
Request.Method = "POST";
byte[] bytes = Encoding.ASCII.GetBytes(formParams);
Request.ContentLength = bytes.Length;
using (Stream os = Request.GetRequestStream())
{
os.Write(bytes, 0, bytes.Length);
}
try
{
resp = Request.GetResponse();
using (StreamReader sr = new StreamReader(resp.GetResponseStream()))
{
String TestResponse = sr.ReadToEnd();
}
}
catch (WebException WE)
{
DebugConsole.AppendText("HTTP Error:" + WE.Message + Environment.NewLine);
String HTML = new StreamReader(WE.Response.GetResponseStream()).ReadToEnd();
DebugConsole.AppendText(HTML);
return null;
}
String cookieHeader = resp.Headers["Set-cookie"];
if (String.IsNullOrEmpty(cookieHeader))
return null;
else
return cookieHeader;
}
This is actually because the web method requires anti csrf (cross site request forgery, more info here: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)) validation parameter. What you can do, is to append the csrf value to the request header:
postHeaders.Add("X-CSRFToken", CSRF);
Maybe you can paste your source code here if you need any help with that, so we can look after it
OK! Solution found!
After getting the response of the Log-In site, search in the "Set-cookie" Header for _xsrf. This is the Token you have to put in the header of the next POST request.

Connecting to a REST webservice in C#

I am not familiar with REST webservices, but I am trying to get a response from one of them in a C# application.
I am trying to connect to the webservice and authenticate my application to get a token. For this, I have an URL, a login and a password.
When I call the authentication method with cURL tool, I get a « success :true» answer, followed with the token string.
But when I try to do the same with my C# code, I always get a « success :false» answer and no token.
Can somebody help me to understand what is missing in my C# code to get the correct answer ? Thank you.
The cURL request (given by the webservice owner) is:
curl -X POST -d "{\"user\":\"mylogin\",\"pwd\":\"mypassword\"}" \
-H "Content-Type: application/json" http://webserviceURL/authenticate
My code is the following : (restlogin, restpassword and resturl are three strings and get the correct values for the connection. The resulting string is obtained in the variable nammed token).
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(resturl + "authenticate");
request.Method = "POST";
request.Credentials = new NetworkCredential(restlogin, restpassword);
request.ContentType = "application/json";
request.Timeout = 30000;
request.ReadWriteTimeout = 30000;
request.Accept = "application/json";
request.ProtocolVersion = HttpVersion.Version11;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
if (response.StatusCode == HttpStatusCode.OK)
{
using (Stream respStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(respStream, Encoding.UTF8);
token = reader.ReadToEnd();
reader.Close();
reader.Dispose();
response.Close();
}
}
As per my comment to the question, you are not sending your credentials in the request body. With request.Credentials you're setting the Authentication Header in your HttpRequest.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(resturl + "authenticate");
request.Method = "POST";
request.ContentType = "application/json";
request.Timeout = 30000;
request.ReadWriteTimeout = 30000;
request.Accept = "application/json";
request.ProtocolVersion = HttpVersion.Version11;
// Set your Response body
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
string json = "{\"user\":\"" + restlogin + "\"," +
"\"pwd\":\"" + restpassword + "\"}";
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
if (response.StatusCode == HttpStatusCode.OK)
{
using (Stream respStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(respStream, Encoding.UTF8);
token = reader.ReadToEnd();
reader.Close();
reader.Dispose();
response.Close();
}
}

C# HTTP Basic Authentication credentials being sent too early

I'm trying to log in to a server (REST API) which uses HTTP Basic Authentication. The request looks like this:
public JObject PerformLogin(string username, string password)
{
string html = string.Empty;
this.username = username;
this.password = password;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(auth_url_internal);
request.AllowAutoRedirect = true;
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
request.Method = "GET";
request.CookieContainer = cookies;
request.KeepAlive = true;
//request.ServicePoint.Expect100Continue = false;
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
request.Headers.Add("Accept-Language", "de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4");
request.PreAuthenticate = true;
request.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested;
string authInfo = username + ":" + password;
authInfo = Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(authInfo));
request.Headers.Add("Authorization", "Basic " + authInfo);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
html = reader.ReadToEnd();
}
JObject jresponse = JObject.Parse(html);
sess_url_internal = jresponse["internalUrl"].ToString();
sess_url_public = jresponse["publicUrl"].ToString();
return jresponse;
}
which basically works, however the credentials are being sent too early.
First I used curl to see what the traffic looks like in detail and found a "Location:"-Header, which means that there is a redirect happening. In detail, the server redirects me from /api/rest/authenticate?version=1.0, which is the authentication URL (lets call it URL1), to /authenticationbasic/login?AlcApplicationUrl=/api/rest/authenticate%3fversion=1.0 (URL2).
However, Chrome sends the Credentials to URL2, where my program sends them to URL1 which is too early, because the server expects them at URL2, where my application doesn't send any and therefore gets a false return.
How can i change that behaviour?
So with the kind help of x... I figured out how to do it:
After the HttpWebResponse response = (HttpWebResponse)request.GetResponse(); simply add
if ((int)response.StatusCode == 302) // redirect
{
/*
Call the function recursively with the new URL, found in
response.Headers["Location"], in my case this would be:
*/
auth_url_internal = response.Headers["Location"];
return PerformLogin(username, password);
}

Very weird error 401?

I am receiving a 401 error I am not anticipating. I am 100% sure the password and usernamne is correct. When I try the it on postman it works, and I get the data I expect. But in this code, the .downloadstring() method returns a 401 error. I created a new harvest account and tried get to that one with the same code, just changed the password and username and I got the API data I wanted. Is there any other reason then wrong password or username error 401 can be cached?
public List<Project> GetAllProjects()
{
uri = "https://bruh.harvestapp.com/projects";
jsonPath = Path.Combine(HostingEnvironment.MapPath("~/App_Data"), "projects.json");
using (WebClient webClient = new WebClient())
{
webClient.Headers[HttpRequestHeader.ContentType] = "application/json";
webClient.Headers[HttpRequestHeader.Accept] = "application/json";
webClient.Headers[HttpRequestHeader.Authorization] = "Basic " + Convert.ToBase64String(new ASCIIEncoding().GetBytes(usernamePassword));
string response = webClient.DownloadString(uri);
projectsList = JsonConvert.DeserializeObject<List<Wrapper>>(response).Select(p => p.project).ToList();
}
return projectsList;
}
According to this C# code sample from harvest, there are a few things that need to be changed:
static void Main(string[] args)
{
HttpWebRequest request;
HttpWebResponse response = null;
StreamReader reader;
StringBuilder sbSource;
// 1. Set some variables specific to your account.
string uri = "https://yoursubdomain.harvestapp.com/projects";
string username="youremail#somewhere.com";
string password="yourharvestpassword";
string usernamePassword = username + ":" + password;
ServicePointManager.ServerCertificateValidationCallback = Validator;
try
{
request = WebRequest.Create(uri) as HttpWebRequest;
request.MaximumAutomaticRedirections = 1;
request.AllowAutoRedirect = true;
// 2. It's important that both the Accept and ContentType headers are
// set in order for this to be interpreted as an API request.
request.Accept = "application/xml";
request.ContentType = "application/xml";
request.UserAgent = "harvest_api_sample.cs";
// 3. Add the Basic Authentication header with username/password string.
request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(new ASCIIEncoding().GetBytes(usernamePassword)));
using (response = request.GetResponse() as HttpWebResponse)
{
if (request.HaveResponse == true && response != null)
{
reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
sbSource = new StringBuilder(reader.ReadToEnd());
// 4. Print out the XML of all projects for this account.
Console.WriteLine(sbSource.ToString());
}
}
}

C# Login to https Website via program

I want to login to website https://ssl.aukro.ua/enter_login.php with following credential parsing and stackoverflow1
I am using following code and it is not working
HttpWebRequest http = WebRequest.Create("https://ssl.aukro.ua/enter_login.php") as HttpWebRequest;
http.KeepAlive = true;
http.Method = "POST";
http.ContentType = "application/x-www-form-urlencoded";
string postData = "user_login=" + "parsing" + "&user_password=" + "stackoverflow1";
byte[] dataBytes = UTF8Encoding.UTF8.GetBytes(postData);
http.ContentLength = dataBytes.Length;
using (Stream postStream = http.GetRequestStream())
{
postStream.Write(dataBytes, 0, dataBytes.Length);
}
HttpWebResponse httpResponse = http.GetResponse() as HttpWebResponse;
// Probably want to inspect the http.Headers here first
http = WebRequest.Create("http://aukro.ua/myaccount/bid.php") as HttpWebRequest;
http.CookieContainer = new CookieContainer();
http.CookieContainer.Add(httpResponse.Cookies);
HttpWebResponse httpResponse2 = http.GetResponse() as HttpWebResponse;
Inspection of the POST when logging in reveals several other parameters:
cod OGZkZlVlNmJk
global_login_hash 83a8ead80c5c544c86c51ab9914db0ab891d7223
session OWFhMANRVl5dVlVUVFoDCAlTBVFQB1QNDVZQVlFTU11cUAVSVFMDDwpRVVVTVgdZCFZSA1JSYmMyOA==
session_login_hash 38d1a6b20f20d7cb7a8cf93d7f3048087d8c9ffb
url ODNiOF5HRxICHE1PQUQdA01YEFcYRlI2MzNi
user_login test
user_password test
version A
You'll need to parse these out of the login page and add them to your post.

Categories