I am using ring
with compojure
and friend
to realize basic password authentication in a toy app. Now I was trying to implement an example and my ring server causes a redirect loop in every browser.
This is my code:
(ns kassenclo.handlers
(:use [ring.util.response]
[ring.middleware.resource]
[ring.middleware.params])
(:require [compojure.core :refer :all]
[compojure.route :as route]
[ring.middleware.session :refer [wrap-session]]
[ring.middleware.keyword-params :refer [wrap-keyword-params]]
[kassenclo.views :as views]
[cemerick.friend :as friend]
[cemerick.friend.workflows :refer [make-auth]]))
(defroutes app
(GET "/" [] views/tally-view)
(GET "/inventory" [] (friend/authorize #{::user} views/inventory-view))
(route/not-found (html [:h1 "This page could not be found, please go back."])))
(defn auth-workflow [request]
(let [speak (get-in request [:params :speak])
credential-fn (get-in request [::friend/auth-config :credential-fn])]
(make-auth (credential-fn speak))))
(defn auth-credential [password]
(if (= password "pass")
{:identity password :roles #{::user}}))
(def handler
(-> app
(friend/authenticate {:workflows [auth-workflow]
:credential-fn auth-credential})
(wrap-keyword-params)
(wrap-params)
(wrap-session)
(wrap-resource "public")))
Simple debugging shows me that the server is alternating between auth-workflow
and auth-credential
a few times before it is stopped. Can anybody point out to me what I am missing?
// Edit:
The curious thing is that this redirect-loop happens on every route, even on /
where friend
is not used in the defroutes
command.
I found out that the make-auth
function, which wraps the authentication-map so it has the correct form has to be applied on the return value of the auth-credential before returning it. If it happens afterwards like in my original post friend rejects it and we get a authentication loop.