How to do DIGEST with POST, PUT and PATCH - c#

I am at a total loss here. Im currently having success doing a GET request against a web service that implements DIGEST MD5-sess authentication. This works fine. I get the expected result so I figure my 'BUILD DIGEST AUTH HEADER' method works as intended.
I then get the requirement to also support POST, PUT and PATCH but now I run into a whole heap of problems. First request obviously returns a 401 and I read the info in the WWW-Authenticate header and make a MD5-sess auth header taking into account that this is now a POST, PUT or PATCH request.
var methodString = urlResolverStrategy.ResolverDataModel.HttpMethod.ToString();
var ha2 = CalculateMd5Hash(string.Format("{0}:{1}", methodString, dir));
I keep everything the same but do also obviously add the content to the request on POST, PUT and PATCH. But for some reason I cannot figure out Im locked out of the service. Second request return another 401 even.
Is there something special that needs to be done for DIGEST Auth when method is POST, PUT and PATCH that Im missing?
I have all my requests setup in Postman as well put Postman does not have the same problem. Second call in Postman gets the expected results. A 200 and the expected data on POST, PUT and PATCH.
Im using a slightly modified version DigestAuthFixer.cs that's also available on some other posts here in stackoverflow.
Code below is currently hardcoded to use the MD5-sess method.
public class DigestAuthFixer
{
private static readonly Random random = new Random(DateTime.Now.Millisecond);
private readonly AuthData authData;
readonly UrlResolverStrategyBase urlResolverStrategy;
public HttpStatusCode StatusCode { get; private set; }
public DigestAuthFixer(BasicAuth basicAuth, UrlResolverStrategyBase urlResolverStrategy)
{
// TODO: Complete member initialization
authData = new AuthData
{
Host = urlResolverStrategy.GetHostName(),
User = basicAuth.GetUsername(),
Password = basicAuth.GetPassword(),
};
this.urlResolverStrategy = urlResolverStrategy;
}
private string CalculateMd5Hash(string input)
{
var inputBytes = Encoding.ASCII.GetBytes(input);
var hash = MD5.Create().ComputeHash(inputBytes);
var sb = new StringBuilder();
foreach (var b in hash)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
private string GrabHeaderVar(string varName, string header)
{
var regHeader = new Regex(string.Format(#"{0}=""([^""]*)""", varName));
var matchHeader = regHeader.Match(header);
if (matchHeader.Success)
{
return matchHeader.Groups[1].Value;
}
throw new ApplicationException(string.Format("Header {0} not found", varName));
}
private string GetDigestHeader(string dir)
{
authData.NC++;
string ha1;
if (authData.Algorithm == "MD5-sess")
{
var ha0 = CalculateMd5Hash(string.Format("{0}:{1}:{2}", authData.User, authData.Realm, authData.Password));
ha1 = CalculateMd5Hash(string.Format("{0}:{1}:{2}", ha0, authData.Nonce, authData.Cnonce));
}
else
{
ha1 = CalculateMd5Hash(string.Format("{0}:{1}:{2}", authData.User, authData.Realm, authData.Password));
}
var methodString = urlResolverStrategy.ResolverDataModel.HttpMethod.ToString();
var ha2 = CalculateMd5Hash(string.Format("{0}:{1}", methodString, dir));
var digestResponse = CalculateMd5Hash(string.Format("{0}:{1}:{2:00000000}:{3}:{4}:{5}", ha1, authData.Nonce, authData.NC, authData.Cnonce, authData.Qop, ha2));
var authString = string.Format("Digest username=\"{0}\", realm=\"{1}\", nonce=\"{2}\", uri=\"{3}\", algorithm=\"{4}\", qop={5}, nc={6:00000000}, cnonce=\"{7}\", response=\"{8}\"", authData.User, authData.Realm, authData.Nonce, dir, authData.Algorithm, authData.Qop, authData.NC, authData.Cnonce, digestResponse);
return authString;
}
public string GrabResponse(string nUrl, string content)
{
var uri = new Uri(authData.Host + nUrl);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = urlResolverStrategy.ResolverDataModel.HttpMethod.ToString();
// If we've got a recent Auth header, re-use it!
if (!string.IsNullOrEmpty(authData.Cnonce) && DateTime.Now.Subtract(authData.CnonceDate).TotalHours < 1.0)
{
request.Headers.Add("Authorization", GetDigestHeader(nUrl));
}
if (!string.IsNullOrEmpty(urlResolverStrategy.ResolverDataModel.IfMatchHeaderValue))
{
request.Headers.Add(HttpHelper.IfMatchHeaderName, urlResolverStrategy.ResolverDataModel.IfMatchHeaderValue);
}
AddContentToBody(request, content);
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
StatusCode = response.StatusCode;
}
catch (WebException ex)
{
// Try to fix a 401 exception by adding a Authorization header
if (ex.Response == null || ((HttpWebResponse)ex.Response).StatusCode != HttpStatusCode.Unauthorized)
throw;
var wwwAuthenticateHeader = ex.Response.Headers["WWW-Authenticate"];
authData.Realm = GrabHeaderVar("realm", wwwAuthenticateHeader);
authData.Nonce = GrabHeaderVar("nonce", wwwAuthenticateHeader);
authData.Qop = GrabHeaderVar("qop", wwwAuthenticateHeader);
authData.Algorithm = "MD5-sess"; // GrabHeaderVar("algorithm", wwwAuthenticateHeader);
authData.NC = 0;
authData.Cnonce = RandomString(8);
authData.CnonceDate = DateTime.Now;
string debug = wwwAuthenticateHeader + Environment.NewLine + nUrl + Environment.NewLine + uri.ToString() + Environment.NewLine + authData.ToString();
var digestRequest = (HttpWebRequest)WebRequest.Create(uri);
digestRequest.Method = urlResolverStrategy.ResolverDataModel.HttpMethod.ToString();
AddContentToBody(digestRequest, content);
var authHeader = GetDigestHeader(nUrl);
debug += uri.ToString() + Environment.NewLine;
debug += nUrl + Environment.NewLine;
debug += authHeader + Environment.NewLine;
digestRequest.Headers.Add("Authorization", authHeader);
if (!string.IsNullOrEmpty(urlResolverStrategy.ResolverDataModel.IfMatchHeaderValue))
{
request.Headers.Add(HttpHelper.IfMatchHeaderName, urlResolverStrategy.ResolverDataModel.IfMatchHeaderValue);
}
HttpWebResponse digestResponse = null;
try
{
//return authHeader;
digestResponse = (HttpWebResponse)digestRequest.GetResponse();
StatusCode = digestResponse.StatusCode;
response = digestResponse;
}
catch (Exception digestRequestEx)
{
if (digestResponse != null)
{
StatusCode = response.StatusCode;
}
else
{
StatusCode = HttpStatusCode.InternalServerError;
}
//return "It broke" + Environment.NewLine + debug;
return "There was a problem with url, username or password (" + digestRequestEx.Message + ")";
}
}
var reader = new StreamReader(response.GetResponseStream());
return reader.ReadToEnd();
}
public string RandomString(int length)
{
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var stringChars = new char[length];
for (int i = 0; i < stringChars.Length; i++)
{
stringChars[i] = chars[random.Next(chars.Length)];
}
return new string(stringChars);
}
private void AddContentToBody(HttpWebRequest request, string content)
{
if (string.IsNullOrEmpty(content))
return;
var data = Encoding.Default.GetBytes(content); // note: choose appropriate encoding
request.ContentLength = data.Length;
request.ContentType = HttpHelper.MediaTypes.Json;
request.Accept = "*/*";
request.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
//request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(content);
}
}
}
internal class AuthData
{
public string Host;
public string User;
public string Password;
public string Realm;
public string Nonce;
public string Qop;
public string Cnonce;
public DateTime CnonceDate;
public int NC;
public string Algorithm;
public override string ToString()
{
string newLine = Environment.NewLine;
string result = Host + newLine;
result += User + newLine;
result += Realm + newLine;
result += Nonce + newLine;
result += Qop + newLine;
result += Cnonce + newLine;
result += CnonceDate + newLine;
result += NC + newLine;
result += Algorithm + newLine;
return result;
}
}

So apparently it matters in which order you add all the headers to the request. With hookbin I was able to detect that even though I have put an Authorization header on my digestRequest object it did not follow through to hookbin.
My placing the Authorization header addition to just below the setting the method line it all works...
I had no idea that that could pose a problem. The reason my GET method work is because is because 'content' is empty so no headers are added.
var digestRequest = (HttpWebRequest)WebRequest.Create(uri);
digestRequest.Method = urlResolverStrategy.ResolverDataModel.HttpMethod.ToString();
digestRequest.Headers.Add("Authorization", GetDigestHeader(nUrl));

Related

AWS TranslateText REST API call adding signature v4

Actually this is not a question, but an answer for those that are trying to use AWS TranslateText without SDK. I have had many problems until I got a running version.
In my opinion, the AWS documentation for this service is not complete and there are not many examples to check (at least for .Net).
At first, I thought I was not generating the correct V4 signature, but after checking the steps and values once again, I decided to use Postman to call the service. It was very helpful.
Postman can generate the AWS signature! (yeah, I did not know) so finally I noticed the signature value was not the problem.
Checking the request I could see the headers needed and some of its values.
The problem in my case was that I was not sending the "x-amz-target" header.
And by chance I found that the value for this header must be "AWSShineFrontendService_20170701.TranslateText"
(I saw a similar value here https://rdrr.io/cran/aws.translate/src/R/translateHTTP.R)
This other link was also helpful
Ivona Request Signing Issue - signature does not match (AWS Signature Version 4)
So now I have a running version, I want to share my .Net code. I hope it helps :) !!
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web.Script.Serialization;
namespace AWS_TranslateTextTest
{
class AWS_TranslateText
{
// Replace this with your own values
const string AccessKey = "AKI_ADD_YOUR_ACCESSKEY";
const string SecretKey = "ADD_YOUR_SECRETKEY";
static void Main()
{
try
{
string text = "Translate this text from English to German.";
string sourceLang = "en";
string targetLang = "de";
string responseText = TranslateText(text, sourceLang, targetLang);
JObject json = JObject.Parse(responseText);
string translatedText = ""; // to do read response from json or responseText
if (json.ToString().Contains("TranslatedText")){
//To access to the properties in "dot" notation use a dynamic object
dynamic obj = json;
translatedText = obj.TranslatedText.Value;
Console.WriteLine("TranslatedText is: {0}", translatedText);
}
else{
Console.WriteLine("TranslatedText not found in response.");
throw new Exception(json.ToString());
}
}
catch (WebException ex)
{
Console.WriteLine(ex.Message);
if (ex.Response != null){
foreach (string header in ex.Response.Headers)
{
Console.WriteLine("{0}: {1}", header, ex.Response.Headers[header]);
}
using (var responseStream = ex.Response.GetResponseStream())
{
if (responseStream != null)
{
using (var streamReader = new StreamReader(responseStream))
{
Console.WriteLine(streamReader.ReadToEnd());
}
}
} }
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static string TranslateText(string text, string sourceLang, string targetLang)
{
var date = DateTime.UtcNow;
const string algorithm = "AWS4-HMAC-SHA256";
const string regionName = "eu-west-1";
const string serviceName = "translate";
const string method = "POST";
const string canonicalUri = "/";
const string canonicalQueryString = "";
const string x_amz_target_header = "AWSShineFrontendService_20170701.TranslateText";
const string contentType = "application/x-amz-json-1.1";
const string host = serviceName + "." + regionName + ".amazonaws.com";
var obj = new
{
SourceLanguageCode = sourceLang,
TargetLanguageCode = targetLang,
Text = text
};
var requestPayload = new JavaScriptSerializer().Serialize(obj);
var hashedRequestPayload = HexEncode(Hash(ToBytes(requestPayload)));
var dateStamp = date.ToString("yyyyMMdd");
var requestDate = date.ToString("yyyyMMddTHHmmss") + "Z";
var credentialScope = string.Format("{0}/{1}/{2}/aws4_request", dateStamp, regionName, serviceName);
var bytes = ToBytes(requestPayload);
var headers = new SortedDictionary<string, string>
{
{"content-length", bytes.Length.ToString()},
{"content-type", contentType},
{"host", host},
{"x-amz-date", requestDate},
{"x-amz-target", x_amz_target_header}
};
string canonicalHeaders =
string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
string signedHeaders =
string.Join(";", headers.Select(x => x.Key.ToLowerInvariant() ));
// Task 1: Create a Canonical Request For Signature Version 4
var canonicalRequest = method + '\n' + canonicalUri + '\n' + canonicalQueryString +
'\n' + canonicalHeaders + '\n' + signedHeaders + '\n' + hashedRequestPayload;
var hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));
// Task 2: Create a String to Sign for Signature Version 4
// StringToSign = Algorithm + '\n' + RequestDate + '\n' + CredentialScope + '\n' + HashedCanonicalRequest
var stringToSign = string.Format("{0}\n{1}\n{2}\n{3}", algorithm, requestDate, credentialScope,
hashedCanonicalRequest);
// Task 3: Calculate the AWS Signature Version 4
// HMAC(HMAC(HMAC(HMAC("AWS4" + kSecret,"20130913"),"eu-west-1"),"tts"),"aws4_request")
byte[] signingKey = GetSignatureKey(SecretKey, dateStamp, regionName, serviceName);
// signature = HexEncode(HMAC(derived-signing-key, string-to-sign))
var signature = HexEncode(HmacSha256(stringToSign, signingKey));
// Task 4: Prepare a signed request
// Authorization: algorithm Credential=access key ID/credential scope, SignedHeadaers=SignedHeaders, Signature=signature
var authorization =
string.Format("{0} Credential={1}/{2}/{3}/{4}/aws4_request, SignedHeaders={5}, Signature={6}",
algorithm, AccessKey, dateStamp, regionName, serviceName, signedHeaders, signature);
// Send the request
string endpoint = "https://" + host; // + canonicalUri ;
var webRequest = WebRequest.Create(endpoint);
webRequest.Method = method;
webRequest.Timeout = 20000;
webRequest.ContentType = contentType;
webRequest.Headers.Add("X-Amz-Date", requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add("X-Amz-Target", x_amz_target_header);
webRequest.ContentLength = bytes.Length;
using (Stream newStream = webRequest.GetRequestStream())
{
newStream.Write(bytes, 0, bytes.Length);
newStream.Flush();
}
var response = (HttpWebResponse)webRequest.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
using (var streamReader = new StreamReader(responseStream))
{
string res = streamReader.ReadToEnd();
return res;
}
}
}
return null;
}
private static byte[] GetSignatureKey(String key, String dateStamp, String regionName, String serviceName)
{
byte[] kDate = HmacSha256(dateStamp, ToBytes("AWS4" + key));
byte[] kRegion = HmacSha256(regionName, kDate);
byte[] kService = HmacSha256(serviceName, kRegion);
return HmacSha256("aws4_request", kService);
}
private static byte[] ToBytes(string str)
{
return Encoding.UTF8.GetBytes(str.ToCharArray());
}
private static string HexEncode(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();
}
private static byte[] Hash(byte[] bytes)
{
return SHA256.Create().ComputeHash(bytes);
}
private static byte[] HmacSha256(String data, byte[] key)
{
return new HMACSHA256(key).ComputeHash(ToBytes(data));
}
}
}

How to Return the HTTP Call Response in C#

I am trying to return the response of productRating in this HTTP call. I have tried several ways but haven't been successful. Any idea? The response is a json with an object that I want to get access to the streamInfo>avgRatings>_overall
public double GetRatings(string productId)
{
const string URL = "https://comments.au1.gigya.com/comments.getStreamInfo";
var apiKey = "3_rktwTlLYzPlqkzS62-OxNjRDx8jYs-kV40k822YlHfEx5VCu93fpUo8JtaKDm_i-";
var categoryId = "product-ratings";
var urlParams = "?apiKey=" + apiKey + "&categoryID=" + categoryId + "&streamID=" + productId + "";
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(URL);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var response = JsonConvert.DeserializeObject(client.GetAsync(urlParams).Result.Content.ReadAsStringAsync().Result);
var productrating = (response["streamInfo"]["avgRatings"]["_overall"]);
return;
}
GetRatings Erroe: not all code paths return a value.
Productrating Error:can not apply indexing with [] to an expression of type HttpResponseMessage
return Error: an object of a type convertable to double is required
ApiCall has to return something. Looking at the example below.
#functions {
public static string ApiCall()
{
return "Hello World!";
}
}
#{
var ratings = ApiCall();
}
#if (ratings != null)
{
<div class="gig-rating-stars" content=#ratings></div>
}
I am using this function for POST API Call and it returns response string and if you want to add security features you can send it in JObject because its the secure channel to send Jobject as a parameter on URL
## Code Start ##
protected string RemoteApiCallPOST(JObject elements, string url)
{
try
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
// JObject jsonResult = new JObject();
string id;
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(elements);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
id = (streamReader.ReadToEnd()).ToString();
return id;
}
}
catch (Exception EX)
{
return "";
}
}
Code End
The only change I needed to do is changing "var" to "dynamic" in :
dynamic response = JsonConvert.DeserializeObject(client.GetAsync(urlParams).Result.Content.ReadAsStringAsync().Result);

C# getting JSON through Cloudflare protection

FIXED - I got this to work by declaring the webclient as a static and then doing the actual call inside a using statement; Now it works if anyone else comes across this. The original issue was it was losing the Cookies after the initial call.
I'm trying to implement the first answer to this question I don't have enough reputation to reply directly to the answer because I just signed up. Also I'm new to C# so this may be easy I hope. I've gotten as far as changing the Regex.Match parameters based on this script but it still doesn't work. Here are the changes I made.
var builder = Regex.Match(html, #"setTimeout\(function\(\){\s+(var s,t,o,p,b,r,e,a,k,i,n,g,f.+?\r?\n[\s\S]+?a\.value =.+?)\r?\n").Groups[1].Value;
builder = Regex.Replace(builder, #"a\.value = (parseInt\(.+?\)).+", "$1");
builder = Regex.Replace(builder, #"\s{3,}[a-z](?: = |\.).+", "");
//Format the javascript..
builder = Regex.Replace(builder, #"[\n\\']", "");
Here's how I'm calling it
private static WebClient ddosclient = null;
public MainWindow()
{
while (ddosclient == null)
{
Console.WriteLine("Trying..");
ddosclient = Cloudflare_Evader.CloudflareEvader.CreateBypassedWebClient("https://yobit.net");
}
using (ddosclient)
{
string tradesuri = "";
string tradesjson = "";
string depthjson = "";
string depthuri = "";
tradersuri = "https://yobit.net/api/3/trades/" + pair;
Console.WriteLine(tradersuri);
tradesjson = ddosclient.DownloadString(tradesuri);
depthuri = "https://yobit.net/api/3/depth/" + pair;
Console.WriteLine(depthuri);
depthjson = ddosclient.DownloadString(depthuri);
}
}
Here's the code from the link,including my edits to the Regex.Match:
using System;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using System.Collections;
using System.Threading;
namespace Cloudflare_Evader
{
public class CloudflareEvader
{
/// <summary>
/// Tries to return a webclient with the neccessary cookies installed to do requests for a cloudflare protected website.
/// </summary>
/// <param name="url">The page which is behind cloudflare's anti-dDoS protection</param>
/// <returns>A WebClient object or null on failure</returns>
public static WebClient CreateBypassedWebClient(string url)
{
var JSEngine = new Jint.Engine(); //Use this JavaScript engine to compute the result.
//Download the original page
var uri = new Uri(url);
HttpWebRequest req =(HttpWebRequest) WebRequest.Create(url);
req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0";
//Try to make the usual request first. If this fails with a 503, the page is behind cloudflare.
try
{
var res = req.GetResponse();
string html = "";
using (var reader = new StreamReader(res.GetResponseStream()))
html = reader.ReadToEnd();
return new WebClient();
}
catch (WebException ex) //We usually get this because of a 503 service not available.
{
string html = "";
using (var reader = new StreamReader(ex.Response.GetResponseStream()))
html = reader.ReadToEnd();
//If we get on the landing page, Cloudflare gives us a User-ID token with the cookie. We need to save that and use it in the next request.
var cookie_container = new CookieContainer();
//using a custom function because ex.Response.Cookies returns an empty set ALTHOUGH cookies were sent back.
var initial_cookies = GetAllCookiesFromHeader(ex.Response.Headers["Set-Cookie"], uri.Host);
foreach (Cookie init_cookie in initial_cookies)
cookie_container.Add(init_cookie);
/* solve the actual challenge with a bunch of RegEx's. Copy-Pasted from the python scrapper version.*/
var challenge = Regex.Match(html, "name=\"jschl_vc\" value=\"(\\w+)\"").Groups[1].Value;
var challenge_pass = Regex.Match(html, "name=\"pass\" value=\"(.+?)\"").Groups[1].Value;
var builder = Regex.Match(html, #"setTimeout\(function\(\){\s+(var s,t,o,p,b,r,e,a,k,i,n,g,f.+?\r?\n[\s\S]+?a\.value =.+?)\r?\n").Groups[1].Value;
builder = Regex.Replace(builder, #"a\.value = (parseInt\(.+?\)).+", "$1");
builder = Regex.Replace(builder, #"\s{3,}[a-z](?: = |\.).+", "");
//Format the javascript..
builder = Regex.Replace(builder, #"[\n\\']", "");
//Execute it.
long solved = long.Parse(JSEngine.Execute(builder).GetCompletionValue().ToObject().ToString());
solved += uri.Host.Length; //add the length of the domain to it.
Console.WriteLine("***** SOLVED CHALLENGE ******: " + solved);
Thread.Sleep(3000); //This sleeping IS requiered or cloudflare will not give you the token!!
//Retreive the cookies. Prepare the URL for cookie exfiltration.
string cookie_url = string.Format("{0}://{1}/cdn-cgi/l/chk_jschl", uri.Scheme, uri.Host);
var uri_builder = new UriBuilder(cookie_url);
var query = HttpUtility.ParseQueryString(uri_builder.Query);
//Add our answers to the GET query
query["jschl_vc"] = challenge;
query["jschl_answer"] = solved.ToString();
query["pass"] = challenge_pass;
uri_builder.Query = query.ToString();
//Create the actual request to get the security clearance cookie
HttpWebRequest cookie_req = (HttpWebRequest) WebRequest.Create(uri_builder.Uri);
cookie_req.AllowAutoRedirect = false;
cookie_req.CookieContainer = cookie_container;
cookie_req.Referer = url;
cookie_req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0";
//We assume that this request goes through well, so no try-catch
var cookie_resp = (HttpWebResponse)cookie_req.GetResponse();
//The response *should* contain the security clearance cookie!
if (cookie_resp.Cookies.Count != 0) //first check if the HttpWebResponse has picked up the cookie.
foreach (Cookie cookie in cookie_resp.Cookies)
cookie_container.Add(cookie);
else //otherwise, use the custom function again
{
//the cookie we *hopefully* received here is the cloudflare security clearance token.
if (cookie_resp.Headers["Set-Cookie"] != null)
{
var cookies_parsed = GetAllCookiesFromHeader(cookie_resp.Headers["Set-Cookie"], uri.Host);
foreach (Cookie cookie in cookies_parsed)
cookie_container.Add(cookie);
}
else
{
//No security clearence? something went wrong.. return null.
//Console.WriteLine("MASSIVE ERROR: COULDN'T GET CLOUDFLARE CLEARANCE!");
return null;
}
}
//Create a custom webclient with the two cookies we already acquired.
WebClient modedWebClient = new WebClientEx(cookie_container);
modedWebClient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0");
modedWebClient.Headers.Add("Referer", url);
return modedWebClient;
}
}
public static CookieCollection GetAllCookiesFromHeader(string strHeader, string strHost)
{
ArrayList al = new ArrayList();
CookieCollection cc = new CookieCollection();
if (strHeader != string.Empty)
{
al = ConvertCookieHeaderToArrayList(strHeader);
cc = ConvertCookieArraysToCookieCollection(al, strHost);
}
return cc;
}
private static ArrayList ConvertCookieHeaderToArrayList(string strCookHeader)
{
strCookHeader = strCookHeader.Replace("\r", "");
strCookHeader = strCookHeader.Replace("\n", "");
string[] strCookTemp = strCookHeader.Split(',');
ArrayList al = new ArrayList();
int i = 0;
int n = strCookTemp.Length;
while (i < n)
{
if (strCookTemp[i].IndexOf("expires=", StringComparison.OrdinalIgnoreCase) > 0)
{
al.Add(strCookTemp[i] + "," + strCookTemp[i + 1]);
i = i + 1;
}
else
al.Add(strCookTemp[i]);
i = i + 1;
}
return al;
}
private static CookieCollection ConvertCookieArraysToCookieCollection(ArrayList al, string strHost)
{
CookieCollection cc = new CookieCollection();
int alcount = al.Count;
string strEachCook;
string[] strEachCookParts;
for (int i = 0; i < alcount; i++)
{
strEachCook = al[i].ToString();
strEachCookParts = strEachCook.Split(';');
int intEachCookPartsCount = strEachCookParts.Length;
string strCNameAndCValue = string.Empty;
string strPNameAndPValue = string.Empty;
string strDNameAndDValue = string.Empty;
string[] NameValuePairTemp;
Cookie cookTemp = new Cookie();
for (int j = 0; j < intEachCookPartsCount; j++)
{
if (j == 0)
{
strCNameAndCValue = strEachCookParts[j];
if (strCNameAndCValue != string.Empty)
{
int firstEqual = strCNameAndCValue.IndexOf("=");
string firstName = strCNameAndCValue.Substring(0, firstEqual);
string allValue = strCNameAndCValue.Substring(firstEqual + 1, strCNameAndCValue.Length - (firstEqual + 1));
cookTemp.Name = firstName;
cookTemp.Value = allValue;
}
continue;
}
if (strEachCookParts[j].IndexOf("path", StringComparison.OrdinalIgnoreCase) >= 0)
{
strPNameAndPValue = strEachCookParts[j];
if (strPNameAndPValue != string.Empty)
{
NameValuePairTemp = strPNameAndPValue.Split('=');
if (NameValuePairTemp[1] != string.Empty)
cookTemp.Path = NameValuePairTemp[1];
else
cookTemp.Path = "/";
}
continue;
}
if (strEachCookParts[j].IndexOf("domain", StringComparison.OrdinalIgnoreCase) >= 0)
{
strPNameAndPValue = strEachCookParts[j];
if (strPNameAndPValue != string.Empty)
{
NameValuePairTemp = strPNameAndPValue.Split('=');
if (NameValuePairTemp[1] != string.Empty)
cookTemp.Domain = NameValuePairTemp[1];
else
cookTemp.Domain = strHost;
}
continue;
}
}
if (cookTemp.Path == string.Empty)
cookTemp.Path = "/";
if (cookTemp.Domain == string.Empty)
cookTemp.Domain = strHost;
cc.Add(cookTemp);
}
return cc;
}
}
public class WebClientEx : WebClient
{
public WebClientEx(CookieContainer container)
{
this.container = container;
}
public CookieContainer CookieContainer
{
get { return container; }
set { container = value; }
}
private CookieContainer container = new CookieContainer();
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest r = base.GetWebRequest(address);
var request = r as HttpWebRequest;
if (request != null)
{
request.CookieContainer = container;
}
return r;
}
protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
{
WebResponse response = base.GetWebResponse(request, result);
ReadCookies(response);
return response;
}
protected override WebResponse GetWebResponse(WebRequest request)
{
WebResponse response = base.GetWebResponse(request);
ReadCookies(response);
return response;
}
private void ReadCookies(WebResponse r)
{
var response = r as HttpWebResponse;
if (response != null)
{
CookieCollection cookies = response.Cookies;
container.Add(cookies);
}
}
}
}

HttpClient's response in Asp.Net returning 404(Not found: Could not find the controller)

I have to authenticate and then request a Web Api in asp.net. The authentication is completed properly. But when I pass the session values to a new request to generate a certain response, the response returns an Controller not found error. I am trying to implement it in Asp.Net MVC application.
Here is the code for the main Index:
public async Task<ActionResult> Index()
{
var result = "";
string json = " { \"username\": \"webservice\", \"password\": \"iIU2piH6wpBF92T\" }";
var request = (HttpWebRequest)WebRequest.Create("https://os.mcparcel.com/osapi/user/login.json");
request.Method = "POST";
request.UserAgent = "MCParcel Plugin";
request.ContentType = "application/json";
using (var s = request.GetRequestStream())
{
using (var stw = new StreamWriter(s))
{
stw.Write(json);
}
}
try
{
var response = (HttpWebResponse)request.GetResponse();
var data = new StreamReader(response.GetResponseStream());
result = data.ReadToEnd();//<-this gives the value for session id and name
string key = "WucHEwRuy7trUDE7u3agEqEWrUkajuCr";
string order_id = "MCParcel3";
int labels_number = 1;
var r = await Test(key, order_id, labels_number, result);
}
catch (WebException ex)
{
var errorData = new StreamReader(ex.Response.GetResponseStream());
var errorString = errorData.ReadToEnd();
}
return View();
}
Here are the other functions inside the same controller, the error is in:
var response
public static async Task<string> Test(string key, string order_id, int labels_number, dynamic results, int? shipment_id = 0)
{
var r = await GetShippingOptionRequest(key, order_id, labels_number, results);
Console.WriteLine(r);
return r;
}
public static async Task<string> GetShippingOptionRequest(string key, string order_id, int labels_number, dynamic results, int? shipment_id = 0)
{
string json = " { \"key\": \"" + key + "\", \"order_id\": \"" + order_id + "\", \"labels_no\": " + labels_number + ", \"shipment_id\": " + shipment_id + "";
var dynObj = JsonConvert.DeserializeObject<LoginResponse>(results);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Method", "POST");
client.DefaultRequestHeaders.Add("ContentType", "application/json");
client.DefaultRequestHeaders.Add("UserAgent", "MCParcel Plugin");
client.DefaultRequestHeaders.Add("sessid", dynObj.sessid);
client.DefaultRequestHeaders.Add("session_name", dynObj.session_name);
client.DefaultRequestHeaders.Add("key", key);
client.DefaultRequestHeaders.Add("order_id", order_id);
client.DefaultRequestHeaders.Add("labels_number", Convert.ToString(labels_number));
client.DefaultRequestHeaders.Add("shipment_id", Convert.ToString(shipment_id));
//the code below is the required response that is not returning values and returning 404 error
var response = await client.GetStringAsync("https://os.mcparcel.com/osapi/service_os_api/get_label_info.json");
return response;
}
}
The response should return something similar to following:
{
"source_labels": ["https://os.mcparcel.com/sites/os.mcparcel.com/files/sourcepdflabels/labels_8c1e3033a8d23c632006639f39ef6964.pdf"],
"tracks": ["https://os.mcparcel.com/track_and_trace/(J)JD0000900581338100135004"],
"labels_file": "https://os.mcparcel.com/sites/os.mcparcel.com/files/pdf_labels/70994c37ad2a99d4047e0684c3e05c1f.pdf"
}
Any help will be highly appreciated. Thanks in advance!!!
Are you able to hit other controllers? If yes, then you might try to create another controller and start moving your current code with simple json request and build it up to complex json request. Or it might also be your routing.
If no, then it might be you have not setup config.MapHttpAttributeRoutes().

error: The stream does not support concurrent IO read or write operations

I am trying to log in to a website from my C# web application to send emails directly from the application instead of making user visit the website personally.
NOTE: The website, I am trying to log into changes the id of the textboxes everytime the page is loaded, EVEN DURING THE SAME SESSION. Therefore I decided to read the page source, extract the id of the textbox and then use that id while posting the message.
public partial class sender : System.Web.UI.Page
{
string userID, userPwd, recepsID, msgText, loginResponseString, sessionCode, queryCode;
private HttpWebRequest initRequest, loginRequest, msgRequest;
private HttpWebResponse initResponse, loginResponse;
private Object lockObj = new Object();
protected void Page_Load(object sender, EventArgs e)
{
userID = Request.QueryString["userNumber"];
userPwd = Request.QueryString["userPwd"];
recepsID = Request.QueryString["receps"];
msgText = Request.QueryString["msgBody"];
if (userID != null && userPwd != null && recepsID != null & msgText != null)
doLoginAndSendMessage(userID, userPwd, recepsID, msgText);
else
Response.Write("Some values are missing");
}
public void doLoginAndSendMessage(string uid, string pwd, string recepIds, string msg)
{
try
{
doLogin(uid, pwd, recepIds, msg);
}
catch (Exception ex)
{
Response.Write("Sending Failed, Please Try Again");
}
}
public void doLogin(string strUserId, string strPassword, string strIds, string strMessage)
{
try
{
initRequest = (HttpWebRequest)WebRequest.Create("http://www.somewebsite.com/login.aspx");
initRequest.CookieContainer = new CookieContainer();
initRequest.Timeout = 60000;
StreamReader initSr = new StreamReader(initRequest.GetResponse().GetResponseStream(), System.Text.Encoding.GetEncoding("utf-8"));
initSr.ReadToEnd();
initSr.Close();
loginRequest = (HttpWebRequest)WebRequest.Create("http://www.somewebsite.com/login.aspx");
loginRequest.CookieContainer = new CookieContainer();
loginRequest.Timeout = 60000;
StringBuilder loginString = new StringBuilder();
loginString.Append("LoginUserId=" + strUserId + "&LoginPassword=" + strPassword + "&RememberMe=1&Login=Login");
byte[] loginData = Encoding.ASCII.GetBytes(loginString.ToString());
//to get any cookies from the initial response
initResponse = (HttpWebResponse)initRequest.GetResponse();
//setting cookies
loginRequest.CookieContainer.Add(initResponse.Cookies);
//Adding Headers
loginRequest.Method = "POST";
loginRequest.ContentType = "application/x-www-form-urlencoded";
loginRequest.ContentLength = loginData.Length;
Stream loginStream = loginRequest.GetRequestStream();
loginStream.Write(loginData, 0, loginData.Length);
loginStream.Close();
//Reading the response
StreamReader loginSr = new StreamReader(loginRequest.GetResponse().GetResponseStream(), System.Text.Encoding.GetEncoding("utf-8"));
loginResponseString = loginSr.ReadToEnd();
loginSr.Close();
if (loginResponseString.Contains("inbox.aspx"))
{
//get session code
sessionCode = loginResponseString.Substring(125, 5);
//call the sendmessage method
sendMessage(strIds, strMessage);
}
else
{
Response.Write("Login Failed: Check Username and password");
}
}
catch (Exception ex)
{
Response.Write("Sending Failed, Please Try Again");
}
}
public void sendMessage(string strIds, string strMsg)
{
try
{
string[] ids = strIds.Split(',');
for (int i = 0; i < ids.Length; i++)
{
msgRequest = (HttpWebRequest)WebRequest.Create("http://www.somewebsite.com/writenew.aspx?sessionid=" + sessionCode);
msgRequest.CookieContainer = new CookieContainer();
msgRequest.Timeout = 1000000;
msgRequest.ReadWriteTimeout = 1000000;
msgRequest.SendChunked = true;
//to get any cookies from the initial response
loginResponse = (HttpWebResponse)loginRequest.GetResponse();
//setting cookies
msgRequest.CookieContainer.Add(loginResponse.Cookies);
//Adding Headers
msgRequest.Method = "POST";
msgRequest.ContentType = "application/x-www-form-urlencoded";
Stream msgStream = msgRequest.GetRequestStream();
Stream respStream = msgRequest.GetResponse().GetResponseStream();
StreamReader codeRead = new StreamReader(respStream, System.Text.Encoding.GetEncoding("utf-8"));
string temp = codeRead.ReadToEnd();
codeRead.Close();
respStream.Close();
txtResponse.Text = temp;
try
{
int starInd = temp.IndexOf("UserId_");
//int endInd = starInd + 15;
string holder = temp.Substring(starInd, 15);
int startInd = holder.IndexOf("_") + 1;
queryCode = holder.Substring(startInd, 5);
txtSubString.Text = queryCode;
}
catch (Exception ex)
{
txtSubString.Text = "SOME ERROR";
}
lock (lockObj)
{
StringBuilder msgString = new StringBuilder();
msgString.Append("sessionid=" + queryCode + "&GlobalKeyId=1&MessageLength=988&ReceiveId_"
+ queryCode + "=" + ids[i] + "&Message_" + queryCode + "=" + strMsg
+ "&SendNow_" + queryCode + "=Send Now");
byte[] msgData = Encoding.ASCII.GetBytes(msgString.ToString());
msgStream.Write(msgData, 0, msgData.Length);
msgStream.Close();
}
//Reading the response
StreamReader msgSr = new StreamReader(respStream, System.Text.Encoding.GetEncoding("utf-8"));
string msgResponseString = msgSr.ReadToEnd();
msgSr.Close();
sessionCode = msgResponseString.Substring(123, 5);
}
Response.Write("Message Sent Successfully");
}
catch (Exception ex)
{
Response.Write("Sending Failed, Please Try Again<br/>" + ex.Message);
}
}
}
The application stops when it reaches this line
msgStream.Write(msgData, 0, msgData.Length);
Please help me solve the error. Thank You
When you call GetResponse() it will cause the request built so far to be sent, and the client to fetch the response.
You need to build your complete request before calling GetResponse(), or your request won't be complete. Getting the request stream and writing POST data after GetResponse() was called will throw this exception to show that continuing building the request after it has already been sent makes no sense.

Categories

Resources