RestSharp - Retrieving Authorization token from POSTed response - c#

I am trying to pass username and password to the following URL :
https://maxcvservices.dnb.com/rest/Authentication
According to the documentation the user_id and password must be passed as headers with the keys: x-dnb-user, x-dnb-pwd respectively.
I thus far have the following code which seems to work but I am unable to retrieve the auth token returned by the response object:
public static void Main (string[] args)
{
var client = new RestClient ("https://maxcvservices.dnb.com/rest/Authentication");
var request = new RestRequest (Method.POST);
request.AddHeader("x-dnb-user", myEmail);
request.AddHeader("x-dnb-pwd", myPassword);
IRestResponse resp = client.Execute(request);
var content = resp.Content;
Console.WriteLine (resp.StatusDescription);
Console.WriteLine (resp.StatusCode);
}
When I try printing the content I get a blank line but what I am actually expecting is the auth token that is returned by the service. A couple of things I think I am doing in the code (but not sure), is passing the userid and password as headers in the POST request which is what is required. The token is returned as the value of the 'Authorization' field in the response object. I was wondering how I might print the token. Also the statusDescription,statusCode both print OK which tells me I have the correct request but am unable to locate the auth token in the response. Any help would be much appreciated in guiding me on how to access the auth token in the Authorization field of the returned POST response.

So you're trying to get the HttpHeader values for Authorization from the IRestResponse object?
You could use e.g. use LINQ for that:
var authroizationHeaderFromResponse = resp.Headers.FirstOrDefault(h => h.Name == "Authorization");
if (authroizationHeaderFromResponse != null)
{
Console.WriteLine(authroizationHeaderFromResponse.Value);
}
Which yields
INVALID CREDENTIALS
You assume that if the response status code is 200 - OK, then there must be a response body accompanying it.
Does the documentation specifically state that you should expect a token in the response body in return?
The D&B developers could send a 200 - OK response with no response body if they want, or they can add their serialized token (JSON, XML etc) elsewhere, e.g. in a header field.
An example of this can be seen in this code from an ASP.NET Web API returning a response from a successful PUT
if (result.Success)
{
var dto = Mapper.Map<TEntity, TDto>(result.Data as TEntity);
var response = Request.CreateResponse(HttpStatusCode.Created, dto);
var uri = Url.Link("DefaultApi", new {id = dto.Id});
response.Headers.Location = new Uri(uri);
return response;
}
This would return a 200 - OK with a serialized object (result.Data) in the response body, but there's nothing wrong with me changing the following
var response = Request.CreateResponse(HttpStatusCode.Created, dto);
To something like
var response = Request.CreateResponse(HttpStatusCode.Created);
That way you would still get a 200 - OK response, but without a response body. This of course is against the recommendations of the HTTP/1.1 Standard for PUT verbs, but it would still work.
I could even do this for giggles
throw new HttpResponseException(HttpStatusCode.Created);
And you would still get a 200 - OK response. Somewhat evil, but possible.
I would suggest trying to fetching data from another resource with the x-dnb-user and x-dnb-pwd header fields set, and check if a response body is returned then. Perhaps D&B was inspired by Basic Authentication when implementing these header fields, and as such require them to be present in every request?
It's worth a try.
Let me know how that works out.

Look in the Headers collection of IRestResponse. It will probably be there rather than the content.
Hth
Oli

It could be that the AUTHTOKEN comes back with the cookies, as this is a common approach.
In this case, you'll need to attach a CookieContanier to your IRestClient, then this container will store the cookies. Provided you use the same client for subsequent requests, that auth cookie will let you in.
private CookieContainer _cookieJar;
...
_cookieJar = new CookieContainer();
_client.CookieContainer = _cookieJar;
You can then inspect the container after a request
_client.PostAsync(MyRequest, (r, h) =>
{
r.Cookies... // inspect em

Related

c# RestSharp: Adding and delete cookie because Statuscode 403

i am currently try to get information of an external API using RestSharp (Version 107.1.2). Unfortunately, in every request I get response Status Code 403 "Forbidden". I now have contact to the provider and he told me, to delete all cookies first and then add the cookie "SMCHALLENGE=YES".
I tried this in RestSharp, but when using the client.AddCookie extension, I receive ArgumentException. I now found another option, to add the cookie in header, but this doesn't work either.
Do you have an idea, how to delete all cookies and then add the SMCHALLENGE cookie?
var client = new RestClient("https://test.de/api/token");
string resource = null;
client.Authenticator = new HttpBasicAuthenticator("testUser", "testPW");
string apiKey = null;
var request = new RestRequest(resource, Method.Get);
//Following execution throws System.ArgumentException: "The {0} parameter cannot be an empty string. Parameter name: cookie.domain"
//client.AddCookie("SMCHALLENGE", "YES");
request.AddHeader("Cookie", "SMCHALLENGE=YES");
var response = client.ExecuteAsync(request);
response.Wait();
RestResponse rr = response.Result;
Thank you very much!
Cookies aren't headers. You need to add your cookies to the RestClient own cookie container. Cookies that are returned in the response will also be available in the cookie container. There's a function on RestClient to do that as a shortcut.
var client = new RestClient("https://test.de/api/token");
client.AddCookie("SMCHALLENGE", "YES");
You can also work with the cookie container:
client.CookieContainer.Add(new Cookie(...));
You'd need to avoid creating a new RestClient instance for each request. This way you'd also keep the cookies across requests.

Differences between using C# HttpClient API and the postman testing? Client call works on postman, but not C# httpClient getAsync

I am testing a REST API post, and it works well when I try it on Postman. However, in some scenario (related to the posting XML data) if I post with HttpClient API, I would receive the following error:
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
But the same XML content works fine on Postman with status OK and proper response.
What is the differences between using the C# HttpClient API and the postman testing? How can I configure my API call to match with the behavior on postman?
Here I attached the source code, and the Postman screenshot
public void createLoan()
{
string baseCreateLoanUrl = #"https://serverhost/create?key=";
var strUCDExport = XDocument.Load(#"C:\CreateLoan_testcase.xml");
using (var client = new HttpClient())
{
var content = new StringContent(strUCDExport.ToString(), Encoding.UTF8, Mediatype);
string createLoanApi = string.Concat(baseCreateLoanUrl, APIKey);
try
{
var response = client.PostAsync(createLoanApi, content).Result;
}
catch (Exception ex)
{
MessageBox.Show("Error Happened here...");
throw;
}
if (response.IsSuccessStatusCode)
{
// Access variables from the returned JSON object
string responseString = response.Content.ReadAsStringAsync().Result;
JObject jObj = JObject.Parse(responseString);
if (jObj.SelectToken("failure") == null)
{
// First get the authToken
string LoanID = jObj["loanStatus"]["id"].ToString();
MessageBox.Show("Loan ID: " + LoanID);
}
else
{
string getTokenErrorMsg = string.Empty;
JArray errorOjbs = (JArray) jObj["failure"]["errors"];
foreach (var errorObj in errorOjbs)
{
getTokenErrorMsg += errorObj["message"].ToString() + Environment.NewLine;
}
getTokenErrorMsg.Dump();
}
}
}
Thanks for Nard's comment, after comparing the header, I found the issue my client header has this:
Expect: 100-continue
While postman doesn't has.
Once I removed this by using the ServicePointManager:
ServicePointManager.Expect100Continue = false;
Everything seems fine now. Thanks all the input!
My gut tells me it's something simple. First, we know the API works, so I'm thinking it's down to how you are using the HttpClient.
First things first, try as suggested by this SO answer, creating it as a singleton and drop the using statement altogether since the consensus is that HttpClient doesn't need to be disposed:
private static readonly HttpClient HttpClient = new HttpClient();
I would think it would be either there or an issue with your content encoding line that is causing issues with the API. Is there something you are missing that it doesn't like, I bet there is a difference in the requests in Postman vs here. Maybe try sending it as JSON ala:
var json = JsonConvert.SerializeObject(strUCDExport.ToString());
var content = new StringContent(json, Encoding.UTF8, Mediatype);
Maybe the header from Postman vs yours will show something missing, I think the real answer will be there. Have fiddler running in the background, send it via Postman, check it, then run your code and recheck. Pay close attention to all the attribute tags on the header from Postman, the API works so something is missing. Fiddler will tell you.
I was struggling with this for 2 days when I stumbled over Fiddler which lets you record the traffic to the service. After comparing the calls I saw that I had missed a header in my code.

cURL and .Net (c#) API Token (Token is Invalid)

I've searched all over the internet and stackoverflow...can't really figure out if it's a code problem or the API is not valid anymore with some tokens...
I've looked through this Stackoverflow thread and tried it out and nothing. The only thing that returns is "TOKEN is invalid".
I'm trying to list the users from this event which has an API here.
This is my code:
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://services.sapo.pt/Codebits/user/1/");
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("&token=NTUyI0FmY29zdGEjYW5kcmVjb3N0NEBnbWFpbC5jb20jZDkwMDdhNWUxOTNiN2VhMzcwMWJjNjI3MjMwMmI2YTQjMTQzMjU2NDU1NSNhMTc3YTdkZjNlYzk2MTg3ZjZmNzk1NTc3YjEwMDExOTcwNDE1ZTZj").Result;
HttpContent responseContent = response.Content;
// //// Get the stream of the content.
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
// // return (await reader.ReadToEndAsync());
if (response.IsSuccessStatusCode)
{
tb1.Text = await reader.ReadToEndAsync();
}
else
{
tb1.Text = "x";
}
}
Since i'm kinda noob, I hope and think it is my problem but I just can't figure it out.
Thanks in advance!
What part of "TOKEN is invalid" is unclear?
Their API help page mentions:
AUTHENTICATION AND USERS
AUTH TOKEN
https://services.sapo.pt/Codebits/gettoken?user=wookiee#sapo.pt&password=grumph
Get the auth token. Will be used as a &token= argument with all the methods that require authentication. Please be aware that tokens may expire (due to timeout, IP change or others). The correct procedure for an app is to ask for a new token if the one it has fails in any of the methods that require authentication.
So when a call fails with "TOKEN is invalid", first make a gettoken call to obtain a valid token.

How to get response data from RestSharp to download for user?

I am using RestSharp to call an HTTP service via a Querystring. The service generates a Word document.
When I call this service, it looks like a Word document is being returned in the "Content" property, but I struggling to work out how to return this content to the user via the traditional download window as a word document for saving.
public ActionResult DocGen(string strReportId)
{
var client = new RestClient("http://localhost:88");
var request = new RestRequest("DocGen/{id}", Method.GET);
request.AddUrlSegment("id", "1060"); // replaces matching token in request.Resource
// execute the request
//RestResponse response = (RestResponse) client.Execute(request);
IRestResponse response = client.Execute(request);
if (response.ErrorException != null)
{
const string message = "Error retrieving response. Check inner details for more info.";
var myException = new ApplicationException(message, response.ErrorException);
throw myException;
}
// Important and simple line. response.rawbytes was what I was missing.
return File(response.RawBytes,response.ContentType,"sample.doc");
}
Should this be an action?
The content type seems correct ie Word.11
So how do I code get this Response.Content back to the user?
Many thanks in advance.
EDIT
I was closer to the solution than I thought. Power to RestSharp I guess !! See above. Now there might be a better way, and I am all ears for any suggestions, but this is where I am at at present.
return File(response.RawBytes,response.ContentType,"sample.doc");
In case anyone may benefit.

obtaining oauth_verifier from callback

I have searched high and low for an answer to this problem. Basically, I am creating a C# application which (In it's first incarnation) will authenticate with the Projectplace API which uses OAuth 1.0a. It currently returns the oauth_verifier to the address bar, but when I use the var response = request.GetResponse(); method, it returns the oauth_token and oauth token_secret which I sent as part of the authorization in the first place.
Perhaps I am misunderstanding the way this process is supposed to work, but I've read every single answer out there and none seem to address this question. Do you have to, or is it possible, to pull the verifier code from the address bar (or wherever else it can be obtained), after I have entered my username and password on the authentication page after callback URL is loaded?
I believe OAuth1.0a requires the verification code to retrieve an access token, and I cannot find a simple way to pull the verification code.
I would really appreciate any help, it's driving me nuts!!
UPDATED 03.12.12
Thanks for your response!
Essentially, I am the client attempting to retrieve the oauth_verifier from the oauth provider after sending this initial request below, my next step is to authorize then retrieve verifier. I tried the following, hopefully as you suggested, like swimming in the deep end here :)
//Generate string for initiation request.
requestUri.AppendFormat("?oauth_consumer_key={0}&", consumerKey);
requestUri.AppendFormat("oauth_nonce={0}&", nonce);
requestUri.AppendFormat("oauth_timestamp={0}&", timeStamp);
requestUri.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
requestUri.AppendFormat("oauth_version={0}&", "1.0");
requestUri.AppendFormat("oauth_signature={0}", signature);
var request = (HttpWebRequest)WebRequest.Create(new Uri(requestUri.ToString()));
request.Method = WebRequestMethods.Http.Get;
var response = request.GetResponse();
var queryString = new StreamReader(response.GetResponseStream()).ReadToEnd();
var parts = queryString.Split('&');
var token = parts[1].Substring(parts[1].IndexOf('=') + 1);
var tokenSecret = parts[0].Substring(parts[0].IndexOf('=') + 1);
var queryString2 = String.Format("oauth_token={0}", token);
//AUTHORIZE WITH CREDENTIALS FROM USER.
var authorizeUrl = "https://api.projectplace.com/authorize?" + queryString;
Process.Start(authorizeUrl);`
//TRY AND READ VERIFICATION STRING AFTER AUTHORIZATION REDIRECT`
String oauthVerifier = HttpContext.Current.Request.QueryString["oauth_verifier"];
Unfortunately, once i've done this, I can't seem to get a querystring returned showing the oauth_verifier that I am clearly seeing in the string showing in the address bar. (Yes it's a very newbish way of describing it, i'm learning the code as well as OAuth :P).
Thanks for your help so far. I tried to run the above, but it just said that says "Object reference not set to an instance of an object.".
Also, if I attempt to use the previous code I used to obtain the querystring / response? from the initiation request using the following lines, the querystring3 just comes back as blank... really frustrating! :)
var queryString3 = new StreamReader(response.GetResponseStream()).ReadToEnd();
var parts3 = queryString3.Split('&');
I'm going to assume that by "in the address bar" you mean that the oauth_verifier is passed to your site from the ProjectPlace server via a query string parameter in the redirect URL. In order to read this in your C# server side code, you would use something like the following (I modified your sample code for this solution):
requestUri.AppendFormat("?oauth_consumer_key={0}&", consumerKey);
requestUri.AppendFormat("oauth_nonce={0}&", nonce);
requestUri.AppendFormat("oauth_timestamp={0}&", timeStamp);
requestUri.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
requestUri.AppendFormat("oauth_version={0}&", "1.0");
requestUri.AppendFormat("oauth_signature={0}", signature);
var request = (HttpWebRequest)WebRequest.Create(new Uri(requestUri.ToString()));
//Note: this is unnecessary - GET is the default
request.Method = WebRequestMethods.Http.Get;
//By casting to HttpWebResponse you get access to the QueryString property
var response = request.GetResponse() as HttpWebResponse;
var oauthVerifier = response.QueryString["oauth_verifier"];
//The response stream contains the HTTP response body,
//which will not contain the URL to which the redirect is sent
//I'm not sure if there is anything there that you will need
var responseBody = new StreamReader(response.GetResponseStream()).ReadToEnd();
//AUTHORIZE WITH CREDENTIALS FROM USER. -- Not sure what this section is doing
var queryString = string.Format("oauth_token={0}", oauthVerifier);
var authorizeUrl = "https://api.projectplace.com/authorize?" + queryString;
Process.Start(authorizeUrl);

Categories

Resources