{-# LANGUAGE Trustworthy #-} {-# LANGUAGE OverloadedStrings #-} -- | Provides HTTP Basic Authentication. module LIO.Web.Simple.Auth ( basicAuth) where import Control.Monad import qualified Data.ByteString.Char8 as S8 import Data.ByteString.Base64 import Network.HTTP.Types import Network.Wai import Web.Simple.Responses import Web.Simple.Controller.Trans -- | A 'Route' that uses HTTP basic authentication to authenticate a -- request for a realm with the given username ans password. The -- request is rewritten with an 'X-User' header containing the -- authenticated username before being passed to the next 'Route'. basicAuth :: Monad m => String -- ^ Realm -> (S8.ByteString -> S8.ByteString -> m Bool) -> SimpleMiddleware m basicAuth realm auth app req = case getBasicAuthLogin req of Nothing -> return authResp Just (usr, pwd) -> do success <- auth usr pwd let req' = req { requestHeaders = ("X-User", usr) : requestHeaders req } if success then app req' else return authResp where authResp = requireBasicAuth realm -- | Helper method for implementing basic authentication. Given a -- 'Request' returns the (username, password) pair from the basic -- authentication header if present. getBasicAuthLogin :: Request -> Maybe (S8.ByteString, S8.ByteString) getBasicAuthLogin req = do authStr <- lookup hAuthorization $ requestHeaders req unless ("Basic" `S8.isPrefixOf` authStr) $ fail "Not basic auth." let up = fmap (S8.split ':') $ decode $ S8.drop 6 authStr case up of Right (user:pwd:[]) -> return (user, pwd) _ -> fail "Malformed basic auth header."