5
votes

I'm trying to understand when the ring anti-forgery token is generated or inserted in an HTML page. I'm using Compojure / ring / hiccup but I take it my question is really about ring. I don't have any problem per se: I just want to know when and how the anti-forgery token is "injected".

The anti-forgery-field function from ring.util.anti-forgery is implemented like this:

(html (hidden-field "__anti-forgery-token" *anti-forgery-token*)

If I call this function at a REPL I get:

REPL>  (println (anti-forgery-field))
<input id="__anti-forgery-token" name="__anti-forgery-token" type="hidden" value="Unbound: #&apos;ring.middleware.anti-forgery/*anti-forgery-token*" />

Still at the REPL, if I try to get this var I get the same "unbound" variable:

> ring.middleware.anti-forgery/*anti-forgery-token*
=> #object[clojure.lang.Var$Unbound 0x1eae055 "Unbound: #'ring.middleware.anti-forgery/*anti-forgery-token*"]

What I don't understand is what that "Unbound" value is nor when it is transformed (by ring?) into an actual token delivered. And I especially don't understand how several users connecting to the website do get, each, a different token (per session).

Is that variable always "unbound"? When/how does it become "bound" (if it does?)?

Also, if I've got the ring session ID (say "ring-session=310678be-9ef6-41a7-a12a-b2417de4a79f"), how can I see, at the Clojure REPL (on the server side), the corresponding anti-forgery token's value?

1
Try reading the source at github.com/ring-clojure/ring-anti-forgery/blob/master/src/ring/…, which isn't doing anything particularly fancy. Once you've done that, if you have specific questions about the mechanism, that will probably be a good question to ask. - amalloy
@amalloy: well I had already read that and I simply don't get it. And this may not be due to me not understanding not only ring but also Clojure (which would explain why using the source didn't help me and why I asked this question). I think a question whose answer would help me understand the mechanism would be: "How can I, from the REPL, read two different anti-forgery token when two users are logged into my website and I know their ring-session ID?". This would really help me understand what's going on under the hood. - Cedric Martin

1 Answers

5
votes

It is bound only in the context (dynamic environment, the current stack, if you will) of the individual request. Think of it as a thread-local variable/binding. You are not in the context of a request while looking at your application state from a REPL.

It must be this way, because it has to be a different value for each user. You'd simulate similar behaviour through an explicit lookup call, if you were working in an environment that does not allow this kind of control of the dynamic environment.

The binding to the right session value is established in the middleware during the request, currently here:

https://github.com/weavejester/ring-anti-forgery/blob/master/src/ring/middleware/anti_forgery.clj#L67

(binding [*anti-forgery-token* (session-token request)]
  ;; ...
  )