(ns yenu.middleware (:require [yenu.env :refer [defaults]] [clojure.tools.logging :as log] [yenu.layout :refer [*app-context* *identity* error-page]] [ring.middleware.anti-forgery :refer [wrap-anti-forgery]] [ring.middleware.webjars :refer [wrap-webjars]] [ring.middleware.format :refer [wrap-restful-format]] [yenu.config :refer [env]] [ring.middleware.flash :refer [wrap-flash]] [ring.middleware.cookies :refer [wrap-cookies]] [immutant.web.middleware :refer [wrap-session]] [ring.middleware.defaults :refer [site-defaults wrap-defaults]] [buddy.auth.middleware :refer [wrap-authentication wrap-authorization]] [buddy.auth.accessrules :refer [wrap-access-rules]] [buddy.auth.backends.session :refer [session-backend]] [buddy.auth.accessrules :refer [restrict]] [ring.util.response :refer [redirect]] [buddy.auth.accessrules :refer [success error]] [buddy.auth :refer [authenticated?]]) (:import [javax.servlet ServletContext])) (defn wrap-context [handler] (fn [request] (binding [*app-context* (if-let [context (:servlet-context request)] ;; If we're not inside a servlet environment ;; (for example when using mock requests), then ;; .getContextPath might not exist (try (.getContextPath ^ServletContext context) (catch IllegalArgumentException _ context)) ;; if the context is not specified in the request ;; we check if one has been specified in the environment ;; instead (:app-context env))] (handler request)))) (defn wrap-internal-error [handler] (fn [req] (try (handler req) (catch Throwable t (log/error t) (error-page {:status 500 :title "Something very bad has happened!" :message "We've dispatched a team of highly trained gnomes to take care of the problem."}))))) (defn wrap-csrf [handler] (wrap-anti-forgery handler {:error-response (error-page {:status 403 :title "Invalid anti-forgery token"})})) (defn wrap-identity [handler] (fn [request] (binding [*identity* (get-in request [:session :identity])] (handler request)))) (defn wrap-formats [handler] (let [wrapped (wrap-restful-format handler {:formats [:json-kw :transit-json :transit-msgpack]})] (fn [request] ;; disable wrap-formats for websockets ;; since they're not compatible with this middleware ((if (:websocket? request) handler wrapped) request)))) (defn on-error [request response] (redirect "/login")) (defn creator-access [request] (let [identity (:identity request)] (if (= identity :creator) true (error "Not a creator.")))) (def rules [{:uris ["/upload" "/statistics" "/comments"] :handler creator-access} {:pattern #"^/.*" :handler authenticated?}]) (defn wrap-auth [handler] (let [backend (session-backend)] (-> handler (wrap-access-rules {:rules rules :on-error on-error}) (wrap-authentication backend) (wrap-authorization backend)))) (defn wrap-base [handler] (-> ((:middleware defaults) handler) wrap-webjars wrap-flash (wrap-session {:cookie-attrs {:http-only true}}) wrap-cookies (wrap-defaults (-> site-defaults (assoc-in [:security :anti-forgery] false) (dissoc :session))) wrap-context wrap-internal-error))