Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to complete POST request in Clojure

I have recently started exploring Clojure and I wanted to set up a simple web app with basic CRUD functionality. I found a nice tutorial here: http://www.xuan-wu.com/2013-09-21-Basic-Web-Application-in-Clojure.

The GET requests work fine, but whenever I attempt a post request, I get the following error:

Invalid anti-forgery token

The tutorial I mentioned earlier does not address anything security related. I did some digging around and it seems like I'm missing some component of Compojure that is supposed to generate a token for making POST requests. Some places mentioned that I was supposed to happen automatically without any changes on my part. I am still not sure what it is that I am missing. Here is my code:

(ns myblog.handler
    (:require [compojure.core :refer :all]
            [compojure.route :as route]
            [ring.middleware.defaults :refer [wrap-defaults site-defaults]]
            [myblog.views :as views]
            [myblog.posts :as posts]
            [ring.util.response :as resp]
            [ring.middleware.basic-authentication :refer :all]))

(defn authenticated? [name pass]
  (and (= name "user")
       (= pass "pass")))

(defroutes public-routes
    (GET "/" [] (views/main-page))
    (route/resources "/"))

(defroutes protected-routes
    (GET "/admin" [] (views/admin-page))
    (GET "/admin/add" [] (views/add-post))
    (POST "/admin/create" [& params]
        (do (posts/create params)
            (resp/redirect "/admin"))))

(defroutes app-routes
    public-routes
    (wrap-basic-authentication protected-routes authenticated?)
    (route/not-found "Not Found"))

(def app
  (wrap-defaults app-routes site-defaults))

Again, only the POST request "/admin/create" is failing with the invalid token error. Any idea what I'm doing wrong?

like image 265
Gregory-Turtle Avatar asked Oct 14 '15 17:10

Gregory-Turtle


2 Answers

Your problem is with the wrap-defaults and site-defaults setting. The site-defaults default configuration adds ant9forgery CSRF protection and any post request which does not include a valid CSRF-token will be blocked.

There are a couple of ways to get around this

  1. Use api-defaults instead of site-defaults. The api-defaults default config is for sites where you are serving up a web API and turns of the CSRF protection included in site-defaults, which is meant for a more traditional web site where post requests are generated by a form which was previously delivered via a get request and includes the csrf-token as a hidden field. The disadvantage of this solution is that it may also disable other middleware you do want to be included

  2. Disable the csrf protection in the site-default config. This involves setting the appropriate key value in the map to false i.e.
    (wrap-defaults app-routes (assoc-in site-defaults [:security :anti-forgery] false))

like image 68
Tim X Avatar answered Nov 15 '22 19:11

Tim X


add a hidden field to your form, example use enlive-html:

(ns xxx.html
  (:use [net.cgrand.enlive-html])
  (:require [clojure.string :as str]
            [ring.util.anti-forgery :refer [anti-forgery-field]]))

(deftemplate render-page "base.html"
  [settings]
  [:form#my-form] (append (html-snippet (anti-forgery-field)))
  ...
)

or disable it, not recommend, as:

(def app (wrap-defaults app-routes (assoc-in site-defaults [:security :anti-forgery] false)))

like image 4
number23_cn Avatar answered Nov 15 '22 18:11

number23_cn