Windows.Web.Http.HttpClient: Receiving cookies and save them - c#

I need some help with the new Windows.Web.Http.HttpClient Class. I am writing my first WP8.1 App right now and it drives me crazy. I am logging into a website like this:
var values = new Dictionary<string, string>();
values.Add("login_username", _username);
values.Add("login_password", _password);
values.Add("login_lifetime", "36000");
var parameters = new HttpFormUrlEncodedContent(values);
var response = await Forum.Http.PostAsync(new Uri("http://foo.bar.xyz"), parameters);
var buffer = await response.Content.ReadAsBufferAsync();
byte[] byteArray = buffer.ToArray();
string content = Encoding.UTF8.GetString(byteArray, 0, byteArray.Length);
if (content.Contains("Wrong password/user name"))
{
return false;
}
return true;
And this works pretty fine. My HttpClient is a static field, like this:
public static HttpBaseProtocolFilter Filter = new HttpBaseProtocolFilter();
public static HttpClient Http = new HttpClient(Filter);
The login works just fine, but it doesn't save the cookies the website sends after logging in. How can I save them and can I send them to the website on every GetAsync()?

You can use HttpClientHandler instead of HttpBaseProtocolFilter. If you must use HttpBaseProtocolFilter, then there is a read-only CookieManager property of type HttpCookieManager that could help you.
Here's an example using HttpClientHandler:
public static CookieContainer Cookies = new CookieContainer();
public static HttpClientHandler HttpClientHandler = new HttpClientHandler() { CookieContainer = Cookies };
public static HttpClient Http = new HttpClient(HttpClientHandler);
After your PostAsync() call returns, you can extract the cookies
var uri = new Uri("http://foo.bar.xyz");
var response = await Forum.Http.PostAsync(uri, parameters);
IEnumerable<Cookie> responseCookies = Cookies.GetCookies(uri).Cast<Cookie>();
foreach (Cookie cookie in responseCookies) {
Console.WriteLine(cookie.Name + ": " + cookie.Value);
}
If you'd like to re-use a cookie from the initial request, you can create your own CookieContainer and copy the cookie from the response cookies. Or - you could also add a hard-coded cookie like this:
Cookies.Add(new HttpCookie("Name", "Value") { Domain="http://foo.bar.xyz" });

Related

HttpClient delivers Location equal to null at redirection (while corresponding browser call contains URL)

I'm getting a cookie and using it, continue to emulate the steps that corresponding browser steps give. Since the auto-redirection is turned off, I have to execute each step individually, fetching the location in the response headers using it in the next. After three such operations, the response's headers contain location field but it's null. Carrying out the corresponding operations using the browser, contains an actual location in every redirection step.
private static Uri ObtainExecutor(Uri referer, Uri uri, Cookie cookie)
{
CookieContainer cookieJar = new CookieContainer();
cookieJar.Add(cookie);
HttpClientHandler handler = new HttpClientHandler
{
CookieContainer = cookieJar,
AllowAutoRedirect = false
};
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Referrer = referer;
client.DefaultRequestHeaders.Host = uri.Host;
HttpResponseMessage response = client.GetAsync(uri).Result;
HttpResponseHeaders headers = response.Headers;
return new Uri(uri, response.Headers.Location);
}
I have no idea how to troubleshoot it further. I've compared the headers noticing nothing of relevance. I've sharked it with the same result, not being able to grasp the overload of packages coming in. Of course, I've googled it for over a week too.
I'm sure there's a tiny difference in how the call is executed but I lack ability to see it. The sample below connects to the actual server and shows the spot where the redirection location is missing. (My apologies for the large sample - I tried to make it minimal but making sure not to leave out a relevant detail unclear to me.)
class Program
{
static void Main(string[] args)
{
const string url = "https://www.pensionsmyndigheten.se/service/login/login"
+ "?targetPage=https://www.pensionsmyndigheten.se/service/overview/"
+ "&failurePage=https://www.pensionsmyndigheten.se/service/login/error/login-failed"
+ "&cancelPage=https://www.pensionsmyndigheten.se/";
Uri uri = new Uri(url);
Cookie cookie = GenerateCookie(uri);
Uri discovery = DiscoverService(cookie);
Uri execution = ObtainExecutor(uri, discovery, cookie);
Uri conversation = ObtainConversor(uri, execution, cookie);
}
private static Cookie GenerateCookie(Uri uri)
{
CookieContainer cookieJar = new CookieContainer();
HttpClientHandler handler = new HttpClientHandler { CookieContainer = cookieJar };
HttpClient client = new HttpClient(handler);
HttpResponseMessage response = client.GetAsync(uri).Result;
HttpContent content = response.Content;
Cookie cookie = cookieJar.GetCookies(uri)
.Cast<Cookie>()
.First(e => e.Name == "pm_retention_urls");
return cookie;
}
private static Uri DiscoverService(Cookie cookie)
{
string url = "https://www.pensionsmyndigheten.se/service/login/discoresponse"
+ "?spId=default"
+ "&entityID=https%3A%2F%2Feid.legitimeringstjanst.se%2Fmobilt-bankid%2F";
Uri uri = new Uri(url);
CookieContainer cookieJar = new CookieContainer();
cookieJar.Add(cookie);
HttpClientHandler handler = new HttpClientHandler
{
CookieContainer = cookieJar,
AllowAutoRedirect = false
};
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Referrer = uri;
client.DefaultRequestHeaders.Host = uri.Host;
HttpResponseMessage response = client.GetAsync(uri).Result;
HttpResponseHeaders headers = response.Headers;
return headers.Location;
}
private static Uri ObtainExecutor(Uri referer, Uri uri, Cookie cookie)
{
CookieContainer cookieJar = new CookieContainer();
cookieJar.Add(cookie);
HttpClientHandler handler = new HttpClientHandler
{
CookieContainer = cookieJar,
AllowAutoRedirect = false
};
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Referrer = referer;
client.DefaultRequestHeaders.Host = uri.Host;
HttpResponseMessage response = client.GetAsync(uri).Result;
HttpResponseHeaders headers = response.Headers;
return new Uri(uri, response.Headers.Location);
}
private static Uri ObtainConversor(Uri referer, Uri uri, Cookie cookie)
{
CookieContainer cookieJar = new CookieContainer();
cookieJar.Add(cookie);
HttpClientHandler handler = new HttpClientHandler
{
CookieContainer = cookieJar,
AllowAutoRedirect = false
};
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Referrer = referer;
client.DefaultRequestHeaders.Host = uri.Host;
HttpResponseMessage response = client.GetAsync(uri).Result;
HttpResponseHeaders headers = response.Headers;
// Figure out why the returned redirection URL is empty.
Uri redirection = headers.Location;
// It should be containing the following value.
redirection = new Uri(
"https://idpproxy.pensionsmyndigheten.se/idp/Authn/SamlSP?conversation=e1s1");
return redirection;
}
}

C# HttpClient Could not verify the provided CSRF token on a POST request

I'm write here because I was trying to send a POST request to a server api,
I tried to send also another request(the first one) and from the response it work({"success":"true", "role":"USER"}). But in the sencond request as a response I get: {"timestamp":1524589409895,"status":403,"error":"Forbidden","message":"Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN'.","path":"/api/v1/rec"}.
So I put all the cookies but one of them "XSRF -TOKEN" cause my program to crashSystem.Net.CookieException: The 'Name'='XSRF -TOKEN' part of the cookie is invalid
so I discovered that this cookie change every time you create a session
so I tried to get the cookies from the response of the first message and added on the header for the second one, and this is the result
I also set the NETFramework at the 4.5 version
I'm leaving a temporary account here for you so you can try this without creating an account only for a test
Request Payload from firefox
static void Main(string[] args)
{
Uri uri = new Uri("https://www.vcast.it/api/v1/rec");
cookieContainer = new CookieContainer();
cookieContainer.Add(uri, new Cookie("CONSENT", "true"));
cookieContainer.Add(uri, new Cookie("_ga", "GA1.2.940742918.1524584758"));
cookieContainer.Add(uri, new Cookie("_gid", "GA1.2.1691132054.1524584758"));
cookieContainer.Add(uri, new Cookie("remember-me", "Z1hvUnJoOHdIM3dCZ2pmYXVKamFRUT09OkpxSXUzRDVRUXd6UG14eGlVUlJMOXc9PQ"));
clienthandler = new HttpClientHandler { AllowAutoRedirect = true, UseCookies = true, CookieContainer = cookieContainer };
client = new HttpClient(clienthandler);
client.DefaultRequestHeaders.Host = "www.vcast.it";
MainAsync();
}
private static CookieContainer cookieContainer;
private static HttpClientHandler clienthandler;
private static HttpClient client;
static async void MainAsync()
{
Uri uri = new Uri("https://www.vcast.it");
var values = new Dictionary<string, string>
{
{ "username", "XXXX" },
{ "password", "XXXX" },
{ "remember-me", "undefined" },
{ "submit", "" }
};
var content = new FormUrlEncodedContent(values);
HttpResponseMessage response = await client.PostAsync("https://www.vcast.it/apiLogin?appId=58aef0c4ea5d52b2c0e4f2ed", content);
Console.WriteLine(await response.Content.ReadAsStringAsync());
Console.WriteLine("New Cookies:");
var responseCookies = cookieContainer.GetCookies(uri).Cast<Cookie>();
foreach (var cook in responseCookies)
{
cookieContainer.Add(uri, cook);
Console.WriteLine(cook.Name + ":" + cook.Value);
}
Console.WriteLine();
clienthandler = new HttpClientHandler { UseCookies = true, CookieContainer = cookieContainer };
client = new HttpClient(clienthandler);
values = JsonConvert.DeserializeObject<Dictionary<string, string>>("{\"name\":\"Titolo registrazione\",\"fromSuggestion\":false,\"manual\":true,\"followSeries\":false,\"resolution\":\"r576\",\"format\":\"MP4\",\"defaultProvider\":\"vcloud\",\"provider\":\"vcloud\",\"channelId\":\"58138235c9e77c00018242ed\",\"startDate\":1524585300000,\"endDate\":1524588900000,\"startHour\":17,\"startMinute\":55,\"endHour\":18,\"endMinute\":55}");
content = new FormUrlEncodedContent(values);
client.DefaultRequestHeaders.Referrer = new Uri("https://www.vcast.it/manualRec/");
response = await client.PostAsync("https://www.vcast.it/api/v1/rec", content);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
I will gladly accept any kind of comment or answer

Read cookie in WPF application

in a wpf application I have to call an external rest service which returns a cookie with session id in it. In all subsequent calls I have to send session id in cookie otherwise it does not return any data.
So how can I retrieve the cookie in wpf code behind class?
CookieContainer cookies = new CookieContainer();
HttpClientHandler handler = new HttpClientHandler();
handler.CookieContainer = cookies;
HttpClient client = new HttpClient(handler);
var domain = EndPoint;
HttpResponseMessage response2 = client.PostAsync(domain, new StringContent(parameters)).Result;
Uri uri = new Uri(domain);
IEnumerable<Cookie> responseCookies = cookies.GetCookies(uri).Cast<Cookie>();
var cookieWithId = responseCookies.Single(o => o.Name == "JESSSIONID");
where EndPoint has http://mydomain.com:38080/workshop/ and parameters has rest/login?username=usr&password=pwd
Here's an example on how to read cookies from response.
CookieContainer cookies = new CookieContainer();
HttpClientHandler handler = new HttpClientHandler();
handler.CookieContainer = cookies;
HttpClient client = new HttpClient(handler);
var domain = "http://yourServiceURL.com";
HttpResponseMessage response = client.GetAsync(domain).Result;
Uri uri = new Uri(domain);
IEnumerable<Cookie> responseCookies = cookies.GetCookies(uri).Cast<Cookie>();
var cookieWithId = responseCookies.Single(o => o.Name == "SessionId");

Get request for my Paypal AccessToken

I am trying to get my access token of paypal.
I have the next parameters: EndPoint, Client Id, secret, api username, api signature, api password, application Id.
should I need a paypal client in order to do it?
I followed this link: https://developer.paypal.com/docs/integration/direct/make-your-first-call/
and tried:
private string getAccessToken() {
var ppClient; // = new paypalClient(); // create a paypal client
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("Accept", "application/json");
parameters.Add("Accept-Language", "en_US");
parameters.Add("grant_type", "client_credentials");
var result = ppClient.Get("https://api.sandbox.paypal.com/v1/oauth2/token", parameters);
string accessToken = result["access_token"];
return accessToken;
}
thank you all!
I would recomend using RestSharp (just grab the NuGet package): -
if (ServicePointManager.SecurityProtocol != SecurityProtocolType.Tls12) ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // forced to modern day SSL protocols
var client = new RestClient(payPalUrl) { Encoding = Encoding.UTF8 };
var authRequest = new RestRequest("oauth2/token", Method.POST) {RequestFormat = DataFormat.Json};
client.Authenticator = new HttpBasicAuthenticator(clientId, secret);
authRequest.AddParameter("grant_type","client_credentials");
var authResponse = client.Execute(authRequest);
Came to this a little late, but ran into similar problem. In the end I had to use a "Basic" authentication implementation to get the details back from PayPal. This is my Token Collector class. The Only thing you really need to do is substitute my PayPal options injection with your 2 paypal client_Id and Secret strings generated in your paypal set up.
Ignore my AccessToken return type, its just a PoCo I made up and the ReadToObject is just a simple deserializer using newtonsoft.
The real good stuff is returned to the 'result' string.
Hope this helps!
public sealed class PaymentTokenServer : IPaymentTokenServer
{
private readonly List<KeyValuePair<string, string>> tokenServerPairs = new List<KeyValuePair<string, string>>();
private PayPalOptions payPalOptions;
public PaymentTokenServer(IOptions<PayPalOptions> paypalOptions)
{
this.payPalOptions = paypalOptions.Value;
this.tokenServerPairs.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
}
public AccessToken GetToken()
{
var content = new FormUrlEncodedContent(this.tokenServerPairs);
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(this.payPalOptions.TokenServerUrl);
client.DefaultRequestHeaders.AcceptLanguage.Add( new StringWithQualityHeaderValue("en_US"));
var base64String = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{this.payPalOptions.ClientId}:{this.payPalOptions.Secret}"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64String);
var response = client.PostAsync("", content).Result;
var result = response.Content.ReadAsStringAsync().Result;
return result.ReadToObject<AccessToken>();
}
}
}

How can I do digest authentication with HttpWebRequest?

Various articles (1, 2) I discovered make this look easy enough:
WebRequest request = HttpWebRequest.Create(url);
var credentialCache = new CredentialCache();
credentialCache.Add(
new Uri(url), // request url
"Digest", // authentication type
new NetworkCredential("user", "password") // credentials
);
request.Credentials = credentialCache;
However, this only works for URLs without URL parameters. For example, I can download http://example.com/test/xyz.html just fine, but when I attempt to download http://example.com/test?page=xyz, the result is a 400 Bad Request message with the following in the server's logs (running Apache 2.2):
Digest: uri mismatch - </test> does not match request-uri </test?page=xyz>
My first idea was that the digest specification requires URL parameters to be removed from the digest hash -- but removing the parameter from the URL passed to credentialCache.Add() didn't change a thing. So it must be the other way around and somewhere in the .NET framework is wrongly removing the parameter from the URL.
You said you removed the querystring paramters, but did you try going all the way back to just the host? Every single example of CredentialsCache.Add() I've seen seems to use only the host, and the docs for CredentialsCache.Add() list the Uri parameter as "uriPrefix", which seems telling.
In other words, try this out:
Uri uri = new Uri(url);
WebRequest request = WebRequest.Create(uri);
var credentialCache = new CredentialCache();
credentialCache.Add(
new Uri(uri.GetLeftPart(UriPartial.Authority)), // request url's host
"Digest", // authentication type
new NetworkCredential("user", "password") // credentials
);
request.Credentials = credentialCache;
If this works, you will also have to make sure that you don't add the same "authority" to the cache more than once... all requests to the same host should be able to make use of the same credential cache entry.
Code taken from this post has worked perfectly for me Implement Digest authentication via HttpWebRequest in C#
I had following issue, when ever I browser the feed url in a browser it asked for username and password and worked fine, however any of the above code samples were not working, on inspecting Request/Response Header (in web developer tools in firefox) i could see header having Authorization of type digest.
Step 1 Add:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using System.Net;
using System.IO;
namespace NUI
{
public class DigestAuthFixer
{
private static string _host;
private static string _user;
private static string _password;
private static string _realm;
private static string _nonce;
private static string _qop;
private static string _cnonce;
private static DateTime _cnonceDate;
private static int _nc;
public DigestAuthFixer(string host, string user, string password)
{
// TODO: Complete member initialization
_host = host;
_user = user;
_password = password;
}
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)
{
_nc = _nc + 1;
var ha1 = CalculateMd5Hash(string.Format("{0}:{1}:{2}", _user, _realm, _password));
var ha2 = CalculateMd5Hash(string.Format("{0}:{1}", "GET", dir));
var digestResponse =
CalculateMd5Hash(string.Format("{0}:{1}:{2:00000000}:{3}:{4}:{5}", ha1, _nonce, _nc, _cnonce, _qop, ha2));
return string.Format("Digest username=\"{0}\", realm=\"{1}\", nonce=\"{2}\", uri=\"{3}\", " +
"algorithm=MD5, response=\"{4}\", qop={5}, nc={6:00000000}, cnonce=\"{7}\"",
_user, _realm, _nonce, dir, digestResponse, _qop, _nc, _cnonce);
}
public string GrabResponse(
string dir)
{
var url = _host + dir;
var uri = new Uri(url);
var request = (HttpWebRequest)WebRequest.Create(uri);
// If we've got a recent Auth header, re-use it!
if (!string.IsNullOrEmpty(_cnonce) &&
DateTime.Now.Subtract(_cnonceDate).TotalHours < 1.0)
{
request.Headers.Add("Authorization", GetDigestHeader(dir));
}
HttpWebResponse response;
try
{
response = (HttpWebResponse)request.GetResponse();
}
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"];
_realm = GrabHeaderVar("realm", wwwAuthenticateHeader);
_nonce = GrabHeaderVar("nonce", wwwAuthenticateHeader);
_qop = GrabHeaderVar("qop", wwwAuthenticateHeader);
_nc = 0;
_cnonce = new Random().Next(123400, 9999999).ToString();
_cnonceDate = DateTime.Now;
var request2 = (HttpWebRequest)WebRequest.Create(uri);
request2.Headers.Add("Authorization", GetDigestHeader(dir));
response = (HttpWebResponse)request2.GetResponse();
}
var reader = new StreamReader(response.GetResponseStream());
return reader.ReadToEnd();
}
}
}
Step 2: Call new method
DigestAuthFixer digest = new DigestAuthFixer(domain, username, password);
string strReturn = digest.GrabResponse(dir);
if Url is: http://xyz.rss.com/folder/rss
then
domain: http://xyz.rss.com (domain part)
dir: /folder/rss (rest of the url)
you could also return it as stream and use XmlDocument Load() method.
The solution is to activate this parameter in apache:
BrowserMatch "MSIE" AuthDigestEnableQueryStringHack=On
More info : http://httpd.apache.org/docs/2.0/mod/mod_auth_digest.html#msie
Then add this property in your code for the webrequest object:
request.UserAgent = "MSIE"
it work very well for me
I think the second URL points to dynamic page and you should first call it using GET to get the HTML and then to download it. No experience in this field though.
In earlier answers everybody use the obsolete WEbREquest.Create method.
So here is my async solution what up to date for recently trending's:
public async Task<string> LoadHttpPageWithDigestAuthentication(string url, string username, string password)
{
Uri myUri = new Uri(url);
NetworkCredential myNetworkCredential = new NetworkCredential(username, password);
CredentialCache myCredentialCache = new CredentialCache { { myUri, "Digest", myNetworkCredential } };
var request = new HttpClient(new HttpClientHandler() { Credentials = myCredentialCache, PreAuthenticate = true});
var response = await request.GetAsync(url);
var responseStream = await response.Content.ReadAsStreamAsync();
StreamReader responseStreamReader = new StreamReader(responseStream, Encoding.Default);
string answer = await responseStreamReader.ReadToEndAsync();
return answer;
}

Categories

Resources