authenticated middleware
This commit is contained in:
+40
-5
@@ -3,15 +3,24 @@
|
|||||||
|
|
||||||
module Middleware where
|
module Middleware where
|
||||||
|
|
||||||
import Data.Aeson
|
import Data.Aeson ((.=), toJSON, ToJSON, object, encode)
|
||||||
|
import Data.Maybe (fromMaybe)
|
||||||
|
|
||||||
import Database.HDBC (runRaw)
|
import Database.HDBC (runRaw)
|
||||||
import Database.HDBC.PostgreSQL (Connection)
|
import Database.HDBC.PostgreSQL (Connection)
|
||||||
import Network.HTTP.Types.Header (hContentType)
|
|
||||||
import Network.HTTP.Types.Status (status400)
|
|
||||||
import Database.HDBC.Types (SqlError(..))
|
import Database.HDBC.Types (SqlError(..))
|
||||||
import Network.Wai (Application, responseLBS)
|
|
||||||
import Control.Exception (finally, throw, catchJust, catch, SomeException)
|
import Data.String.Conversions(cs)
|
||||||
|
import qualified Data.ByteString.Char8 as BS
|
||||||
|
import Control.Exception (finally, throw, catchJust, catch, SomeException,
|
||||||
|
bracket_)
|
||||||
|
|
||||||
|
import Network.HTTP.Types.Header (RequestHeaders, hContentType, hAuthorization)
|
||||||
|
import Network.HTTP.Types.Status (status400, status401)
|
||||||
|
import Network.Wai (Application, requestHeaders, responseLBS)
|
||||||
|
|
||||||
|
import PgQuery(LoginAttempt(..), signInRole, setRole, resetRole)
|
||||||
|
import Codec.Binary.Base64.String (decode)
|
||||||
|
|
||||||
|
|
||||||
inTransaction :: (Connection -> Application) -> (Connection -> Application)
|
inTransaction :: (Connection -> Application) -> (Connection -> Application)
|
||||||
@@ -24,6 +33,32 @@ withSavepoint app conn req respond = do
|
|||||||
catch (app conn req respond) (\e -> let _ = (e::SomeException) in
|
catch (app conn req respond) (\e -> let _ = (e::SomeException) in
|
||||||
runRaw conn "rollback to savepoint req_sp" >> throw e)
|
runRaw conn "rollback to savepoint req_sp" >> throw e)
|
||||||
|
|
||||||
|
authenticated :: BS.ByteString -> (Connection -> Application)
|
||||||
|
-> Connection -> Application
|
||||||
|
authenticated anon app conn req respond = do
|
||||||
|
attempt <- httpRequesterRole (requestHeaders req)
|
||||||
|
case attempt of
|
||||||
|
MalformedAuth ->
|
||||||
|
respond $ responseLBS status400 [] "Malformed basic auth header"
|
||||||
|
LoginFailed ->
|
||||||
|
respond $ responseLBS status401 [] "Invalid username or password"
|
||||||
|
LoginSuccess role ->
|
||||||
|
bracket_ (setRole conn role) (resetRole conn) $ app conn req respond
|
||||||
|
NoCredentials ->
|
||||||
|
bracket_ (setRole conn anon) (resetRole conn) $ app conn req respond
|
||||||
|
|
||||||
|
where
|
||||||
|
httpRequesterRole :: RequestHeaders -> IO LoginAttempt
|
||||||
|
httpRequesterRole hdrs = do
|
||||||
|
let auth = fromMaybe "" $ lookup hAuthorization hdrs
|
||||||
|
case BS.split ' ' (cs auth) of
|
||||||
|
("Basic" : b64 : _) ->
|
||||||
|
case BS.split ':' $ cs (decode $ cs b64) of
|
||||||
|
(u:p:_) -> signInRole u p conn
|
||||||
|
_ -> return MalformedAuth
|
||||||
|
_ -> return NoCredentials
|
||||||
|
|
||||||
|
|
||||||
instance ToJSON SqlError where
|
instance ToJSON SqlError where
|
||||||
toJSON t = object [
|
toJSON t = object [
|
||||||
"error" .= object [
|
"error" .= object [
|
||||||
|
|||||||
Reference in New Issue
Block a user