Very weird error 401? - c#

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());
}
}
}

Related

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);
}

c# httpwebrequest for basic authentication

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...

Test Basic Authentication in C#

How do I test if user supplied correct username/password for basic authentication?
I have this code to retrieve a page. If authentication is valid, it works fine
public static bool can_login(string user_name, string password)
{
WebResponse response = null;
StreamReader reader = null;
string result = null;
string login_url = "https://httpbin.org/basic-auth/user/passwd";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(login_url);
request.Method = "GET";
// Set the basic auth
string authInfo = user_name + ":" + password;
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
request.Headers["Authorization"] = "Basic " + authInfo;
response = request.GetResponse(); // Throws System.Net.WebException if login invalid
reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
result = reader.ReadToEnd();
return false;
}
Is there a foolproof way to test for correctness or should I just catch exception and hope its about the credentials?

The remote server returned an error: (401) Unauthorized when requesting RestApi data

I am triyng to get data from the Rest API. API wants 3 things to give authentication;
first one is "Accept:application/vnd.###.v1.0+json"
second one : "Content Type : application/json"
third one : Base64 encoded "userName:password" string
and I should pass these credentials for validation and authorization in custom header.I know there are a lot of thread on this site about this topic but I couldn't solve the problem from them.
Here is the code block :
public class McAfeeIPSManager
{
String URL = "https://serviceOfApi/sdkapi/session";
public void getWebRequest()
{
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
String username = "user";
String password = "password1";
var request = HttpWebRequest.Create(URL) as HttpWebRequest;
request.Accept = "application/vnd.###.v2.0+json";
request.Method = "GET";
request.ContentType = "application/json";
String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
request.Headers.Add("Authorization","Basic "+encoded);
try
{
// Get response
using (var response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
using (var responseReader = new StreamReader(response.GetResponseStream()))
{
string responseBody = responseReader.ReadToEnd();
// Console application output
System.Diagnostics.Debug.Write("Response Body ---> " + responseBody);
//Console.WriteLine(responseBody);
}
}
}
catch (WebException ex)
{
System.Diagnostics.Debug.Write("Error : " + ex.Message);
Console.WriteLine("Error: {0}", ex.Message);
}
}
}
How can get data from WebAPI under these conditions?Can anybody help me?
You have no PreAuthenticate and credential ?
I have a code that may help you:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://pwmaffr2:8443/remote/system.delete?names=" + DeviceName + "");
request.Headers.Add("AUTHORIZATION", "Basic YTph");
request.ContentType = "text/html";
request.Credentials = new NetworkCredential(Username, Password);
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
request.PreAuthenticate = true;
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
);
StreamReader stream = new StreamReader(response.GetResponseStream());
string X = stream.ReadToEnd();
hmm in addition of what i post try deal with this it should work for you hope:
string credentials = String.Format("{0}:{1}", username, password);
byte[] bytes = Encoding.ASCII.GetBytes(credentials);
string base64 = Convert.ToBase64String(bytes);
string authorization = String.Concat("basic ", base64);
request.Headers.Add("Authorization", authorization);

oauth/token returns empty body

I am encountering a problem getting the access_token in client application using oauth.
The returned response has empty body though in API I can see the response is not empty.
tokenresponse = {
"access_token":"[ACCESSTOKENVALUE]",
"token_type":"bearer",
"expires_in":"1200",
"refresh_token":"[REFRESHTOKENVALUE]",
"scope":"[SCOPEVALUE]"
}
The method from API that returns the token http://api.sample.com/OAuth/Token:
public ActionResult Token()
{
OutgoingWebResponse response =
this.AuthorizationServer.HandleTokenRequest(this.Request);
string tokenresponse = string.Format("Token({0})", response!=null?response.Body:""));
return response.AsActionResult();
}
The client method that requests the token is:
public string GetAuthorizationToken(string code)
{
string Url = ServerPath + "OAuth/Token";
string redirect_uri_encode = UrlEncode(ClientPath);
string param = string.Format("code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type=authorization_code",code, ClientId, ClientSecret, redirect_uri_encode);
HttpWebRequest request = HttpWebRequest.Create(Url) as HttpWebRequest;
string result = null;
request.Method = "POST";
request.KeepAlive = true;
request.ContentType = "application/x-www-form-urlencoded";
request.Timeout = 10000;
request.Headers.Remove(HttpRequestHeader.Cookie);
var bs = Encoding.UTF8.GetBytes(param);
using (Stream reqStream = request.GetRequestStream())
{
reqStream.Write(bs, 0, bs.Length);
}
using (WebResponse response = request.GetResponse())
{
var sr = new StreamReader(response.GetResponseStream());
result = sr.ReadToEnd();
sr.Close();
}
if (!string.IsNullOrEmpty(result))
{
TokenData tokendata = JsonConvert.DeserializeObject<TokenData>(result);
return UpdateAuthorizotionFromToken(tokendata);
}
return null;
}
The result variable is empty.
Please let me know if you have any idea what could cause this. Initially I assumed is because of the cookies so I tried to remove them from request.
Thanks in advance.
Dear just create webclient using following code and you will get json info in tokeninfo.I used it and simply its working perfect.
WebClient client = new WebClient();
string postData = "client_id=" + ""
+ "&client_secret=" + ""
+ "&grant_type=password&username=" + "" //your username
+ "&password=" + "";//your password :)
string soundCloudTokenRes = "https://api.soundcloud.com/oauth2/token";
string tokenInfo = client.UploadString(soundCloudTokenRes, postData);
You can then use substring that contains only token from tokeninfo.
To upload tracks on sound cloud.
private void TestSoundCloudupload()
{
System.Net.ServicePointManager.Expect100Continue = false;
var request = WebRequest.Create("https://api.soundcloud.com/tracks") as HttpWebRequest;
//some default headers
request.Accept = "*/*";
request.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
request.Headers.Add("Accept-Language", "en-US,en;q=0.8,ru;q=0.6");
//file array
var files = new UploadFile[] { new UploadFile(Server.MapPath("Downloads//0.mp3"), "track[asset_data]", "application/octet-stream") };
//other form data
var form = new NameValueCollection();
form.Add("track[title]", "Some title");
form.Add("track[sharing]", "public");
form.Add("oauth_token", "");
form.Add("format", "json");
form.Add("Filename", "0.mp3");
form.Add("Upload", "Submit Query");
try
{
using (var response = HttpUploadHelper.Upload(request, files, form))
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
Response.Write(reader.ReadToEnd());
}
}
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
}

Categories