Skip to content

Instantly share code, notes, and snippets.

@asakasinsky
Forked from raek/auth.clj
Created March 4, 2023 19:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save asakasinsky/073eb711f927ece0c155c6b3a8f92c59 to your computer and use it in GitHub Desktop.
Save asakasinsky/073eb711f927ece0c155c6b3a8f92c59 to your computer and use it in GitHub Desktop.
HTTP Basic Authentication Ring Middleware
(ns se.raek.rhea.auth
(:use [ring.util.codec :only (base64-decode)]))
(defn parse-credentials
"Extracts the user name and password from a HTTP Basic Authentication header
value and returns them in a vector.
Example:
(parse-credentials \"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\")
=> [\"Aladdin\" \"open sesame\"]"
[auth-header-value]
{:pre [(or (nil? auth-header-value)
(string? auth-header-value))]}
(when auth-header-value
(when-let [[_ creds-b64]
(re-find #"^[Bb][Aa][Ss][Ii][Cc] (.*)$" auth-header-value)]
(let [creds-string (String. (base64-decode creds-b64) "US-ASCII")]
(when-let [[_ user pass]
(re-find #"^([^:]*):(.*)$" creds-string)]
[user pass])))))
(defn wrap-basic-auth
"Decorator for HTTP Basic Authentication. This middleware sets the given key
to the value returned by auth-fn when called with the username and password
as arguments. auth-fn should take two arguments, the username and the
password, and return something that identifies the user, if the credentials
are valid."
[handler auth-fn]
(fn [{:keys [headers], :as request}]
(if-let [[user pass] (parse-credentials (get headers "authorization"))]
(handler (assoc request :user (auth-fn user pass)))
(handler (assoc request :user nil)))))
(defn wrap-require-auth
[handler realm]
(let [realm-string (format "Basic realm=\"%s\"" realm)
entity-string (format "Authentication Required for Realm \"%s\"" realm)]
(fn [{:keys [user], :as request}]
(if user
(handler request)
{:status 401
:headers {"WWW-Authenticate" realm-string
"Content-Type" "text/plain"}
:body entity-string}))))
(defn reset-auth
[realm]
(let [realm-string (format "Basic realm=\"%s\"" realm)]
(fn [request]
{:status 401
:headers {"WWW-Authenticate" realm-string
"Content-Type" "text/plain"}
:body "Use this page to force your browser to ask for credentials"})))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment