Problems setting / reading cookie in django - ajax

I'm trying to set a persistent cookie for several consecutive requests. The idea is that if a request does not contain the cookie in the first place, a uuid4 identifier is set in a cookie under 'mykey' and the response is sent. This all happens via requests made to a REST api from a javascript client.
I can see the cookie when inspecting the response on my browser, but if I issue a second request—which should not set a new cookie, as 'mykey' is already populated—the cookie is reset with a new uuid4 identifier.
This is the code:
def some_view(request):
cookie = request.get_signed_cookie('mykey', salt='foobar', default=False)
# do stuff
response = HttpResponse(content='foo')
if not cookie:
value = str(uuid.uuid4())
response.set_signed_cookie('mykey', value, salt='foobar')
return response
Any ideas? Thnx!
A.

With the signed cookies, you are probably running into problems with HTTPOnly. You could try this:
set_signed_cookie(key, value, salt='', httponly=False)

Related

Deleting all cookies

I'm having a difficult time deleting all cookies using the following code. What seems to happen is that the domain is changed to append a dot in front of it. Instead of deleting all cookies, I get duplicate cookies with slightly different domains. Is there any way to completely remove all cookies no matter what their domain looks like?
Thanks for any help!
//DeleteCookies deletes all cookies
func DeleteCookies(w http.ResponseWriter, r *http.Request) {
for _, c := range r.Cookies() {
deleted := &http.Cookie{
Name: c.Name,
Path: c.Path,
//Expires: time.Unix(0, 0),
MaxAge: -10,
HttpOnly: c.HttpOnly,
Domain: c.Domain,
Secure: c.Secure,
Value: "",
}
http.SetCookie(w, deleted)
}
}
What you try to do doesn't work well as cookies do not work that way.
The easy things first:
HttpOnly, Domain and Secure: These values are not transmitted in a HTTP client request, these fields of c will always be empty. The client uses these fields to determine whether to send a (Name,Value)-pair in the Cookie header or not but doesn't send these values.
For HttpOnly, Secure (and SameSite) this does not matter as these (and MaxAge and Expires) do not contribute to the cookie identity.
Cookie identity is based on the tripple (Domain,Path,Name) as sent in a SetCookie header. Often Domain and Path are implicit but they do have defined values on the client.
Now to delete a cookie with identity (Domain-X, Path-X, Name-X) you must send a cookie with the same identity (Domain-X, Path-X, Name-X) and MaxAge=-1. But as explained above the cookie you receive doesn't contain Domain and Path.
There are two ways out:
You must know whether your cookies are domain or host cookies and which path they were set for and use that information to delete them. (I would recommend this.)
Delete all possible cookies. Upon a request to path /foo/bar/wuz the cookies from the client might stem from path /, /foo or /foo/bar (if I remember correctly; test and look it up in RFC 6265). So delete the cookie with name "Name-X" for all these paths. Do the same for the Domain attribute which unfortunately is more complicated. Delete the host cookie (Domain=="") and delete the domain cookies (Domain!=""). Make sure to get the right domain name (the effective TLD plus one).
As you see 2 is pretty complicated. But that is how cookies are designed: The server is expected to know what cookies the servers sets i.e. the server is expected to know the cookie identity (Domain,Path,Name) of all its cookies. The responsibility of the client is to send back the appropriate (Name,Value) pair for a certain request only. If the server wishes to delete a cookie it just sets MaxAge of that cookie to -1. Note that "that cookie" is something the server is expected to know and not infer from a client request.

okhttp3: cookieJar: how to have saveFromResponse always called with all response cookies

It looks like cookieJar.saveFromResponse(...) will not be called if Cookie.parseAll(...) returns an empty Cookie List: (https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/internal/http/HttpEngine.java#L867)
and Cookie.parseAll(...) excludes response cookies based on domain matching and other logic:(https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/Cookie.java#L302)
Is it possible to bypass the Cookie.parse domain matching logic so that cookieJar.saveFromResponse(...) is called with response cookies that haven't been whittled down by domain?

setting cookie for use in warden. "invalid cookie value"

I am writing specs for my api and am manually writing a http request.
I am trying to set a cookie by adding the following key-val header
cookies
cookies: {
'warden.user.user.key' => ActiveSupport::JSON.encode(
[[session_data[0]], session_data[1]]
)
}
That's a String-String key-val pair, but the value is invalid. I get ArgumentError: Invalid cookie value for the JSON-serialized value (which ends up as
"\"[[Xy2LppWrQ53yHmpxVOkF7w], $2a$10$a/kS05VaSlNv2wwBXPfGU.]\""
I honestly have no idea how to fix this. I am trying to make a cookie with this format because in my Controller, I figured out that the session cookie is stored in warden.user.user.key and the value is a nested array of [[object_uid], session_token]
Appreciate whatever help! thanks
If it makes any difference, I am using airborne to make the requests (which uses rest-client under the hood, but doesn't throw errors on non-OK status codes.)
In the bigger picture I'm just trying to pass a session token to warden, which is used by devise.

Maintaining session and cookies over a 302 redirect

I am trying to make fetch a PDF file that gets generated on-demand behind an auth wall. Based on my testing, the flow is as follows:
I make a GET request with several parameters (including auth credentials) to the appropriate page. That page validates my credentials and then processes my request. When the request is finished processing (nearly instantly), I am sent a 302 response that redirects me to the location of the generated PDF. This PDF can then only be accessed by that session.
Using a browser, there's really nothing strange that happens. I attempted to do the same via curl and wget without any optional parameters, but those both failed. I was able to get curl working by adding -L -b /tmp/cookie.txt as options, though (to follow redirects and store cookies).
According to the ruby-doc, using Net::HTTP.start should get me close to what I want. After playing around with it, I was indeed fairly close. I believe the only issue, however, was that my Set-Cookie values were different between requests, even though they were using the same http object in the same start block.
I tried keeping it as simple as possible and then expanding once I got the results I was looking for:
url = URI.parse("http://dev.example.com:8888/path/to/page.jsp?option1=test1&option2=test2&username=user1&password=password1")
Net::HTTP.start(url.host, url.port) do |http|
# Request the first URL
first_req = Net::HTTP::Get.new url
first_res = http.request first_req
# Grab the 302 redirect location (it will always be relative like "../servlet/sendfile/result/543675843657843965743895642865273847328.pdf")
redirect_loc = URI.parse(first_res['Location']
# Request the PDF
second_req = Net::HTTP::Get.new redirect_loc
second_res = http.request first_req
end
I also attempted to use http.get instead of creating a new request each time, but still no luck.
The problem is with cookie: it should be passed within the second request. Smth like:
second_req = Net::HTTP::Get.new(uri.path, {'Cookie' => first_req['Set-Cookie']})

Ruby's open-uri and cookies

I would like to store the cookies from one open-uri call and pass them to the next one. I can't seem to find the right docs for doing this. I'd appreciate it if you could tell me the right way to do this.
NOTES: w3.org is not the actual url, but it's shorter; pretend cookies matter here.
h1 = open("http://www.w3.org/")
h2 = open("http://www.w3.org/People/Berners-Lee/", "Cookie" => h1.FixThisSpot)
Update after 2 nays: While this wasn't intended as rhetorical question I guarantee that it's possible.
Update after tumbleweeds: See (the answer), it's possible. Took me a good while, but it works.
I thought someone would just know, but I guess it's not commonly done with open-uri.
Here's the ugly version that neither checks for privacy, expiration, the correct domain, nor the correct path:
h1 = open("http://www.w3.org/")
h2 = open("http://www.w3.org/People/Berners-Lee/",
"Cookie" => h1.meta['set-cookie'].split('; ',2)[0])
Yes, it works. No it's not pretty, nor fully compliant with recommendations, nor does it handle multiple cookies (as is).
Clearly, HTTP is a very straight-forward protocol, and open-uri lets you at most of it. I guess what I really needed to know was how to get the cookie from the h1 request so that it could be passed to the h2 request (that part I already knew and showed). The surprising thing here is how many people basically felt like answering by telling me not to use open-uri, and only one of those showed how to get a cookie set in one request passed to the next request.
You need to add a "Cookie" header.
I'm not sure if open-uri can do this or not, but it can be done using Net::HTTP.
# Create a new connection object.
conn = Net::HTTP.new(site, port)
# Get the response when we login, to set the cookie.
# body is the encoded arguments to log in.
resp, data = conn.post(login_path, body, {})
cookie = resp.response['set-cookie']
# Headers need to be in a hash.
headers = { "Cookie" => cookie }
# On a get, we don't need a body.
resp, data = conn.get(path, headers)
Thanks Matthew Schinckel your answer was really useful. Using Net::HTTP I was successful
# Create a new connection object.
site = "google.com"
port = 80
conn = Net::HTTP.new(site, port)
# Get the response when we login, to set the cookie.
# body is the encoded arguments to log in.
resp, data = conn.post(login_path, body, {})
cookie = resp.response['set-cookie']
# Headers need to be in a hash.
headers = { "Cookie" => cookie }
# On a get, we don't need a body.
resp, data = conn.get(path, headers)
puts resp.body
Depending on what you are trying to accomplish, check out webrat. I know it is usually used for testing, but it can also hit live sites, and it does a lot of the stuff that your web browser would do for you, like store cookies between requests and follow redirects.
you would have to roll your own cookie support by parsing the meta headers when reading and adding a cookie header when submitting a request if you are using open-uri. Consider using httpclient http://raa.ruby-lang.org/project/httpclient/ or something like mechanize instead http://mechanize.rubyforge.org/ as they have cookie support built in.
There is a RFC 2109 and RFC 2965 cookie jar implementation to be found here for does that want standard compliant cookie handling.
https://github.com/dwaite/cookiejar

Resources