I am working in a Windows Phone 8 PCL project. I am using a 3rd party REST API and I need to use a few HttpOnly cookies originated by the API. It seems like getting/accessing the HttpOnly cookies from HttpClientHandler's CookieContainer is not possible unless you use reflection or some other backdoor.
I need to get these cookies and send them in subsequent requests otherwise I am not going to be able to work with this API - how can I accomplish this? Here is what my current request code looks like:
Thanks in advance.
//Some request
HttpRequestMessage request = new HttpRequestMessage();
HttpClientHandler handler = new HttpClientHandler();
//Cycle through the cookie store and add existing cookies for the susbsequent request
foreach (KeyValuePair<string, Cookie> cookie in CookieManager.Instance.Cookies)
{
handler.CookieContainer.Add(request.RequestUri, new Cookie(cookie.Value.Name, cookie.Value.Value));
}
//Send the request asynchronously
HttpResponseMessage response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
//Parse all returned cookies and place in cookie store
foreach (Cookie clientcookie in handler.CookieContainer.GetCookies(request.RequestUri))
{
if (!CookieManager.Instance.Cookies.ContainsKey(clientcookie.Name))
CookieManager.Instance.Cookies.Add(clientcookie.Name, clientcookie);
else
CookieManager.Instance.Cookies[clientcookie.Name] = clientcookie;
}
HttpClient httpClient = new HttpClient(handler);
The HttpOnly cookie is inside the CookieContainer, it's only that is not exposed. If you set the same instance of that CookieContainer to the next request it will set the hidden cookie there (as long as the request is made to the same site the cookie specifies).
That solution will work until you need to serialize and deserialize the CookieContainer because you are restoring state. Once you do that you lose the HttpOnly cookies hidden inside the CookieContainer. So, a more permanent solution would be using Sockets directly for that request, read the raw request as a string, extract the cookie and set it to the next requests. Here's the code for using Sockets in Windows Phone 8:
public async Task<string> Send(Uri requestUri, string request)
{
var socket = new StreamSocket();
var hostname = new HostName(requestUri.Host);
await socket.ConnectAsync(hostname, requestUri.Port.ToString());
var writer = new DataWriter(socket.OutputStream);
writer.WriteString(request);
await writer.StoreAsync();
var reader = new DataReader(socket.InputStream)
{
InputStreamOptions = InputStreamOptions.Partial
};
var count = await reader.LoadAsync(512);
if (count > 0)
return reader.ReadString(count);
return null;
}
There is also a second possibility - to manually go through response headers, grab and then parse Set-Cookie headers using a bunch of custom code.
It looks something like that, when you are going to match and save a single PHPSESSID cookie (assume LatestResponse is your HttpResponseMessage containing website response):
if (LatestResponse.Headers.ToString().IndexOf("Set-Cookie:") != -1) try
{
string sid = LatestResponse.Headers.ToString();
sid = sid.Substring(sid.IndexOf("Set-Cookie:"), 128);
if (sid.IndexOf("PHPSESSID=") != -1)
{
settings.Values["SessionID"] = SessionID = sid.Substring(sid.IndexOf("PHPSESSID=") + 10, sid.IndexOf(';') - sid.IndexOf("PHPSESSID=") - 10);
handler.CookieContainer.Add(new Uri("http://example.com", UriKind.Absolute), new System.Net.Cookie("PHPSESSID", SessionID));
}
} catch (Exception e) {
// your exception handling
}
Note this code inserts the cookie to CookieContainer for that object's life unless manually deleted. If you want to include it in a new object, just pull the right setting value and add it to your new container.
Related
How do I parse a response cookie and sent back a specific value into a request header?
I'm making a request: it's sending back a token in a session cookie (token=longstrong). I need to grab that cookie, parse out token, and send back the value in a x-token: request header for following requests.
Paw is only giving me the option to send the cookie (raw).
How can I parse the response cookie to send back the value of $.token (json pseudo-code)?
A late reply, sorry!
This might help (from How do i pick specific cookies?):
Use a Custom dynamic value (right click on the field, and pick Extensions > Custom), instead, and use the following JavaScript code snippet:
function evaluate(context){
// Set here the cookies you'd like to return
var wantedCookies = ["datr", "reg_fb_ref"];
var regex = /^(\w+)\=([^;\s]+)/g;
// Request
// Uses here the current request, you can use getRequestByName("name of the request") instead
var request = context.getCurrentRequest();
// Get response cookies
var cookies = request.getLastExchange().getResponseHeaderByName("Set-Cookie").split(", ");
var filteredCookies = [];
for (var i in cookies) {
var cookie = cookies[i];
var match = regex.exec(cookie);
if (match && wantedCookies.indexOf(match[1]) >= 0) {
filteredCookies.push(match[0]);
}
}
return filteredCookies.join(",");
};
That basically parses manually the response cookies, and returns the ones you need.
This other question might help: Routes using cookie authentication from previous version of Paw no longer work on new version
I configured Identity Server:
public void Configuration(IAppBuilder app)
{
var factory = new IdentityServerServiceFactory().UseInMemoryClients(new Client[] {
new Client()
{
ClientName = "MyClient",
ClientId = "MyClientId",
Enabled = true,
Flow = Flows.Implicit,
RedirectUris = new List<string> { "MyClientServer/callback" },
};
});
}
and client server:
public void Configuration(IAppBuilder app)
{
var cookieOptions = new CookieAuthenticationOptions();
cookieOptions.AuthenticationType = "Cookies";
app.UseCookieAuthentication(cookieOptions);
var authenticationOptions = new OpenIdConnectAuthenticationOptions() {
Authority = "https://MyIdentityServer/core",
ClientId = "MyClientId",
SignInAsAuthenticationType = "Cookies",
UseTokenLifetime = true,
RedirectUri = "MyClientServer/callback"
});
app.UseOpenIdConnectAuthentication(authenticationOptions);
}
When user login with "Remember Me" option Identity cookie has expired date:
idsvr.session expires 04 October ...
But client cookie does not:
.AspNet.Cookies at end of session
What should I do to set the same expiration date to client cookie?
UPDATE:
I can set any expiration date in client application:
authenticationOptions.Provider = new CookieAuthenticationProvider()
{
OnResponseSignIn = (context) =>
{
var isPersistent = context.Properties.IsPersistent;
if (isPersistent) // Always false
{
context.CookieOptions.Expires = DateTime.UtcNow.AddDays(30);
}
}
};
But I cannot determine when to set expiration date. It should be set only when user selects "Remember Me", but IsPersistent option always false on client side.
The problem exists on simple boilerplate project too:
https://identityserver.github.io/Documentation/docsv2/overview/mvcGettingStarted.html
UPDATE2:
I need client cookie to be persistent because of bug in Safari - https://openradar.appspot.com/14408523
Maybe some workaround exists, so I can pass expiration date in callback from Identity to Client?
UPDATE3:
Actually, our Identity and Client servers have same parent domain like app.server.local and id.server.local. Maybe I can pass expiration date via additional cookie that belongs to parent domain (.server.local)? But I have no idea where it can be written on Identity, and where it can be applied on Client.
A cookie issued by IdentityServer and a cookie issued by a client application are not linked in any way. IdentityServer does not have any control over cookies in a client application.
When you log in to IdentityServer, you are issued a cookie that tracks the authenticated user within IdentityServer. This saves the user from entering their credentials for every client application, facilitating single sign on.
By default this cookie lasts for that session (so it expires once the browser closes), otherwise if you set "remember me" it will last for a set number of days, across sessions.
A cookie in a client application would be issued upon successful verification of an identity token from IdentityServer. This cookie can have any expiration time, any policy, any name. It's completely controlled by the client application. In your case client cookie expiration can be set in the CookieAuthenticationOptions in your client application.
You need to handle the cookie auth events. The open id middleware just creates an auth cookie, so you can handle all aspects of this cookie from those events. You'll need to look at the events and with a little trial and error you should be able to manage the cookie lifetime.
You can do it at the java-script by using following code in here I have created this cookie to expires within 14 days.
var exdate = new Date();
exdate.setDate(exdate.getDate() + 14);
document.cookie = "yourcookie=" + yourCookieValue + ";expires=" + exdate.toUTCString() + ";";
As i am either too dump to find the proper answer or it is simply not out there ... how the hek i replace the "outdated" WebRequest properly with the HttpClient "replacement"?
In the WebRequest i tendet to serialize & analyze the actual cookie as the webpage returns a partial JSON cookie ... however ... i still did not found a way to get a proper CookieContainer (or whatever form of cookie) from the frking HttpClient ... also ... every google request leads me to 20000000 years old answers or outdated documents (+ some upToDate docs which all just refer to "GET" requests without any cookies involved -.-*))
would be kindfull if somebody could lead me to the correct path ...
thx
greets
X39
Windows.Web.Http.HttpClient client = new Windows.Web.Http.HttpClient();
client.DefaultRequestHeaders.UserAgent.TryParseAdd(app.Settings.UserAgent);
var response = await client.PostAsync(new Uri(app.Settings.Pr0grammUrl.Api + "user/login"), new Windows.Web.Http.HttpStringContent(postDataBuilder.ToString()));
By default, HttpClient handles cookies by itself through the default HttpBaseProtocolFilter. You can get cookies associated with a URI through GetCookies method of the HttpCookieManager class:
Gets an HttpCookieCollection that contains the HttpCookie instances
that are associated with a specific URI.
using (var protocolFilter = new HttpBaseProtocolFilter()) {
var cookieManager = protocolFilter.CookieManager;
var cookies = cookieManager.GetCookies(uri);
foreach (var cookie in cookies) {
// Here is each cookie
}
}
You should also be able to set/get cookies through HTTP request and response headers. To disallow HttpClient from handling cookies by itself, create an instance of HttpBaseProtocolFilter and set the CookieUsageBehavior to HttpCookieUsageBehavior.NoCookies:
NoCookies: Do not handle cookies automatically.
// Create http filter
httpFilter = new HttpBaseProtocolFilter();
httpFilter.CookieUsageBehavior = HttpCookieUsageBehavior.NoCookies;
// Create http client
httpClient = new HttpClient(httpFilter);
// Handle cookies through HTTP headers
I am trying to Post and get a cookie. I am a newbie and this is a learning project for me. My impression is that if you use 'set-cookie' one should be able to see an additional 'set-cookie' in the .toSource. (I am trying to accomplish this on Google Apps Site if that makes a difference.) Am I missing something? Here is my code:
function setGetCookies() {
var payload = {'set-cookie' : 'test'};
var opt2 = {'headers':payload, "method":"post"};
UrlFetchApp.fetch("https://sites.google.com/a/example.com/blacksmith", opt2);
var response = UrlFetchApp.fetch("https://sites.google.com/a/example.com/blacksmith")
var openId = response.getAllHeaders().toSource();
Logger.log(openId)
var AllHeaders = response.getAllHeaders();
for (var prop in AllHeaders) {
if (prop.toLowerCase() == "set-cookie") {
// if there's only one cookie, convert it into an array:
var myArray = [];
if ( Array.isArray(AllHeaders[prop]) ) {
myArray=AllHeaders[prop];
} else {
myArray[0]=AllHeaders[prop];
}
// now process the cookies
myArray.forEach(function(cookie) {
Logger.log(cookie);
});
break;
}
}
}
Thanks in advance! I referenced this to develop the code: Cookie handling in Google Apps Script - How to send cookies in header?
Open to any advice.
When you aren't logged in Google Sites won't set any cookies in the response. UrlFetchApp doesn't pass along your Google cookies, so it will behave as if you are logged out.
First the cookie you want to send whose name is 'test' does not have a value. You should send 'test=somevalue'.
Second I am wondering if you are trying to send the cookie to the googlesite server and ask it to reply with the same cookie you previously sent... ?
I am thinking you are trying to act as a HTTP server beside you are a HTTP client.
As a HTTP client your role is only to send back any cookies that the HTTP server have previously sent to you (respecting the domain, expiration... params).
I'm having trouble creating a non-persistent cookie using the FormsAuthenticationTicket. I want to store userdata in the ticket, so i can't use FormsAuthentication.SetAuthCookie() or FormsAuthentication.GetAuthCookie() methods. Because of this I need to create the FormsAuthenticationTicket and store it in a HttpCookie.
My code looks like this:
DateTime expiration = DateTime.Now.AddDays(7);
// Create ticket
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(2,
user.Email,
DateTime.Now,
expiration,
isPersistent,
userData,
FormsAuthentication.FormsCookiePath);
// Create cookie
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));
cookie.Path = FormsAuthentication.FormsCookiePath;
if (isPersistent)
cookie.Expires = expiration;
// Add cookie to response
HttpContext.Current.Response.Cookies.Add(cookie);
When the variable isPersistent is true everything works fine and the cookie is persisted. But when isPersistent is false the cookie seems to be persisted anyway. I sign on in a browser window, closes it and opens the browser again and I am still logged in. How do i set the cookie to be non-persistent?
Is a non-persistent cookie the same as a session cookie? Is the cookie information stored in the sessiondata on the server or are the cookie transferred in every request/response to the server?
Try deleting:
if (isPersistent)
{ cookie.Expires = expiration; }
... and replacing it with:
if (!isPersistent) {
cookie.Expires = DateTime.Now.AddYears(-1); }