yenu/src/clj/yenu/middleware.clj

101 lines
3.5 KiB
Clojure

(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]]
[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 wrap-auth [handler]
(let [backend (session-backend)]
(-> handler
(wrap-access-rules {:rules rules :on-error on-error})
(wrap-authentication backend)
(wrap-authorization backend))))
(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-base [handler]
(-> ((:middleware defaults) handler)
wrap-webjars
wrap-flash
(wrap-session {:cookie-attrs {:http-only true}})
(wrap-defaults
(-> site-defaults
(assoc-in [:security :anti-forgery] false)
(dissoc :session)))
wrap-context
wrap-internal-error))