1
votes

I've struggled for a few days trying to get a simple use of the security library, Friend, to work with the Chestnut clj/cljs template.

A POST request to the the /login uri is supposed log me in and allow access the protected routes like /role-user. But for some reason I am not able to login, the POST returns a 303 and routes me back to the root page.

I added the Friend middleware inside the http-handler function. Is this the correct place to apply this sort of middleware? I thought maybe the reload or api-defaults middleware could be messing up friend middleware? However, removing them does not fix things.

(def http-handler
  (if is-dev?
    (-> #'routes
        (reload/wrap-reload)
        (friend/authenticate
          {:allow-anon? true
           :login-uri "/login"
           :default-landing-uri "/"
           :unauthorized-handler #(-> (h/html5 [:h2 "You do not have sufficient privileges to access " (:uri %)])
                                      resp/response
                                      (resp/status 401))
           :credential-fn (fn [x]
                            (let [res (creds/bcrypt-credential-fn @users x)]
                              (log/info x)
                              (log/info res)
                              res))
           :workflows [(workflows/interactive-form)]})
        (wrap-defaults api-defaults))
    (wrap-defaults routes api-defaults)))

Based on the print statements I was able to figure out that the credential-fn function does get called on the POST request, with the correct params, and the function returns the correct (authenticated) result.

This http-handler is used as such

(defn run-web-server [& [port]]
  (let [port (Integer. (or port (env :port) 10555))]
    (print "Starting web server on port" port ".\n")
    (run-jetty http-handler {:port port :join? false})))

(defn run-auto-reload [& [port]]
  (auto-reload *ns*)
  (start-figwheel))

(defn run [& [port]]
  (when is-dev?
    (run-auto-reload))
  (run-web-server port))

For what it's worth, here are my routes.

(defroutes routes
  (GET "/" req
    (h/html5
      misc/pretty-head
      (misc/pretty-body
       (misc/github-link req)
       [:h3 "Current Status " [:small "(this will change when you log in/out)"]]
       [:p (if-let [identity (friend/identity req)]
             (apply str "Logged in, with these roles: "
               (-> identity friend/current-authentication :roles))
             "anonymous user")]
       login-form
       [:h3 "Authorization demos"]
       [:ul
        [:li (e/link-to (misc/context-uri req "role-user") "Requires the `user` role")]]
       [:p (e/link-to (misc/context-uri req "logout") "Click here to log out") "."])))
  (GET "/login" req
    (h/html5 misc/pretty-head (misc/pretty-body login-form)))
  (GET "/logout" req
    (friend/logout* (resp/redirect (str (:context req) "/"))))
  (GET "/role-user" req
    (friend/authorize #{::users/user} "You're a user!")))
1
I figured it out. (wrap api-defaults) does not allow sessions and Friend is trying to use them. I should be using site-defaults instead. See ring middleware for more info. - currentoor
Post this as an answer that you can accept, so this question doesn't appear to be unanswered anymore. - schaueho

1 Answers

1
votes

I figured it out. (wrap api-defaults) does not allow sessions and Friend is trying to use them. I should be using site-defaults instead. See ring middleware for more info.