IP Whitelist OR HTTP Basic Auth with Ring
Oct 28, 2018
For work I recently needed to implement scenario: The web app should be freely acessible within the office (which has a static IP address to the world) OR from home using HTTP basic auth. This wasn’t super straightfoward, so here is my implementation:
I used two ring libraries:
with these deps.edn
coordinates:
net.danielcompton/ring-ip-whitelist {:mvn/version "0.2.1"}
ring-basic-authentication {:mvn/version "1.0.5"}
To implement my specific scheme, I pulled out the pieces I needed and wrapped them up in a new ring middleware:
(require '[ring.middleware.basic-authentication :refer [authentication-failure basic-authentication-request]]
'[ring.middleware.ip-whitelist :refer [ip-in-ip-set? build-ip-set]])
(def office-ip "123.123.123.123")
(def allowed-users-password-pairs #{["max" "coffee"]
["jane" "latte"]})
(defn basic-auth-authenticated?
"Checks if the username/password combination is valid"
[name pass]
(allowed-users-password-pairs [name pass]))
(defn ip-whitelisted? [whitelist req]
"Checks if the IP is in the whitelist. Also works with CIDR blocks."
(ip-in-ip-set? (build-ip-set whitelist) (:remote-addr req)))
(defn wrap-auth [handler]
(fn [req]
(if-not (ip-whitelisted? [office-ip] req)
(do
(let [auth-req (basic-authentication-request req basic-auth-authenticated?)]
(if (:basic-authentication auth-req)
(handler auth-req) ; authenticated!
(authentication-failure)))) ; no authentication. Present challenge
(do ; ip is whitelisted
(handler req)))))