{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
module Auth.Biscuit.Servant
(
RequireBiscuit
, authHandler
, genBiscuitCtx
, checkBiscuit
, checkBiscuitM
, WithAuthorizer (..)
, handleBiscuit
, withAuthorizer
, withAuthorizer_
, withAuthorizerM
, withAuthorizerM_
, noAuthorizer
, noAuthorizer_
, withFallbackAuthorizer
, withPriorityAuthorizer
, withFallbackAuthorizerM
, withPriorityAuthorizerM
, module Biscuit
) where
import Auth.Biscuit as Biscuit
import Data.Kind (Type)
import Control.Applicative (liftA2)
import Control.Monad.Except (MonadError, throwError)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Reader (ReaderT, lift, runReaderT)
import Data.Bifunctor (first)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as C8
import qualified Data.ByteString.Lazy as LBS
import Network.Wai
import Servant (AuthProtect)
import Servant.Server
import Servant.Server.Experimental.Auth
type RequireBiscuit = AuthProtect "biscuit"
type instance AuthServerData RequireBiscuit = Biscuit OpenOrSealed Verified
data WithAuthorizer (m :: Type -> Type) (a :: Type)
= WithAuthorizer
{ WithAuthorizer m a -> ReaderT (Biscuit OpenOrSealed Verified) m a
handler_ :: ReaderT (Biscuit OpenOrSealed Verified) m a
, WithAuthorizer m a -> m Authorizer
authorizer_ :: m Authorizer
}
withFallbackAuthorizer :: Functor m
=> Authorizer
-> WithAuthorizer m a
-> WithAuthorizer m a
withFallbackAuthorizer :: Authorizer -> WithAuthorizer m a -> WithAuthorizer m a
withFallbackAuthorizer Authorizer
newV h :: WithAuthorizer m a
h@WithAuthorizer{m Authorizer
authorizer_ :: m Authorizer
authorizer_ :: forall (m :: * -> *) a. WithAuthorizer m a -> m Authorizer
authorizer_} =
WithAuthorizer m a
h { authorizer_ :: m Authorizer
authorizer_ = (Authorizer -> Authorizer -> Authorizer
forall a. Semigroup a => a -> a -> a
<> Authorizer
newV) (Authorizer -> Authorizer) -> m Authorizer -> m Authorizer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m Authorizer
authorizer_ }
withFallbackAuthorizerM :: Applicative m
=> m Authorizer
-> WithAuthorizer m a
-> WithAuthorizer m a
withFallbackAuthorizerM :: m Authorizer -> WithAuthorizer m a -> WithAuthorizer m a
withFallbackAuthorizerM m Authorizer
newV h :: WithAuthorizer m a
h@WithAuthorizer{m Authorizer
authorizer_ :: m Authorizer
authorizer_ :: forall (m :: * -> *) a. WithAuthorizer m a -> m Authorizer
authorizer_} =
WithAuthorizer m a
h { authorizer_ :: m Authorizer
authorizer_ = (Authorizer -> Authorizer -> Authorizer)
-> m Authorizer -> m Authorizer -> m Authorizer
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 Authorizer -> Authorizer -> Authorizer
forall a. Semigroup a => a -> a -> a
(<>) m Authorizer
authorizer_ m Authorizer
newV }
withPriorityAuthorizer :: Functor m
=> Authorizer
-> WithAuthorizer m a
-> WithAuthorizer m a
withPriorityAuthorizer :: Authorizer -> WithAuthorizer m a -> WithAuthorizer m a
withPriorityAuthorizer Authorizer
newV h :: WithAuthorizer m a
h@WithAuthorizer{m Authorizer
authorizer_ :: m Authorizer
authorizer_ :: forall (m :: * -> *) a. WithAuthorizer m a -> m Authorizer
authorizer_} =
WithAuthorizer m a
h { authorizer_ :: m Authorizer
authorizer_ = (Authorizer
newV Authorizer -> Authorizer -> Authorizer
forall a. Semigroup a => a -> a -> a
<>) (Authorizer -> Authorizer) -> m Authorizer -> m Authorizer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m Authorizer
authorizer_ }
withPriorityAuthorizerM :: Applicative m
=> m Authorizer
-> WithAuthorizer m a
-> WithAuthorizer m a
withPriorityAuthorizerM :: m Authorizer -> WithAuthorizer m a -> WithAuthorizer m a
withPriorityAuthorizerM m Authorizer
newV h :: WithAuthorizer m a
h@WithAuthorizer{m Authorizer
authorizer_ :: m Authorizer
authorizer_ :: forall (m :: * -> *) a. WithAuthorizer m a -> m Authorizer
authorizer_} =
WithAuthorizer m a
h { authorizer_ :: m Authorizer
authorizer_ = (Authorizer -> Authorizer -> Authorizer)
-> m Authorizer -> m Authorizer -> m Authorizer
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 Authorizer -> Authorizer -> Authorizer
forall a. Semigroup a => a -> a -> a
(<>) m Authorizer
newV m Authorizer
authorizer_ }
withAuthorizer :: Applicative m
=> Authorizer
-> ReaderT (Biscuit OpenOrSealed Verified) m a
-> WithAuthorizer m a
withAuthorizer :: Authorizer
-> ReaderT (Biscuit OpenOrSealed Verified) m a
-> WithAuthorizer m a
withAuthorizer Authorizer
v ReaderT (Biscuit OpenOrSealed Verified) m a
handler_ =
WithAuthorizer :: forall (m :: * -> *) a.
ReaderT (Biscuit OpenOrSealed Verified) m a
-> m Authorizer -> WithAuthorizer m a
WithAuthorizer
{ ReaderT (Biscuit OpenOrSealed Verified) m a
handler_ :: ReaderT (Biscuit OpenOrSealed Verified) m a
handler_ :: ReaderT (Biscuit OpenOrSealed Verified) m a
handler_
, authorizer_ :: m Authorizer
authorizer_ = Authorizer -> m Authorizer
forall (f :: * -> *) a. Applicative f => a -> f a
pure Authorizer
v
}
withAuthorizerM :: m Authorizer
-> ReaderT (Biscuit OpenOrSealed Verified) m a
-> WithAuthorizer m a
withAuthorizerM :: m Authorizer
-> ReaderT (Biscuit OpenOrSealed Verified) m a
-> WithAuthorizer m a
withAuthorizerM m Authorizer
authorizer_ ReaderT (Biscuit OpenOrSealed Verified) m a
handler_ =
WithAuthorizer :: forall (m :: * -> *) a.
ReaderT (Biscuit OpenOrSealed Verified) m a
-> m Authorizer -> WithAuthorizer m a
WithAuthorizer
{ ReaderT (Biscuit OpenOrSealed Verified) m a
handler_ :: ReaderT (Biscuit OpenOrSealed Verified) m a
handler_ :: ReaderT (Biscuit OpenOrSealed Verified) m a
handler_
, m Authorizer
authorizer_ :: m Authorizer
authorizer_ :: m Authorizer
authorizer_
}
withAuthorizer_ :: Monad m => Authorizer -> m a -> WithAuthorizer m a
withAuthorizer_ :: Authorizer -> m a -> WithAuthorizer m a
withAuthorizer_ Authorizer
v = Authorizer
-> ReaderT (Biscuit OpenOrSealed Verified) m a
-> WithAuthorizer m a
forall (m :: * -> *) a.
Applicative m =>
Authorizer
-> ReaderT (Biscuit OpenOrSealed Verified) m a
-> WithAuthorizer m a
withAuthorizer Authorizer
v (ReaderT (Biscuit OpenOrSealed Verified) m a -> WithAuthorizer m a)
-> (m a -> ReaderT (Biscuit OpenOrSealed Verified) m a)
-> m a
-> WithAuthorizer m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> ReaderT (Biscuit OpenOrSealed Verified) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift
withAuthorizerM_ :: Monad m => m Authorizer -> m a -> WithAuthorizer m a
withAuthorizerM_ :: m Authorizer -> m a -> WithAuthorizer m a
withAuthorizerM_ m Authorizer
v = m Authorizer
-> ReaderT (Biscuit OpenOrSealed Verified) m a
-> WithAuthorizer m a
forall (m :: * -> *) a.
m Authorizer
-> ReaderT (Biscuit OpenOrSealed Verified) m a
-> WithAuthorizer m a
withAuthorizerM m Authorizer
v (ReaderT (Biscuit OpenOrSealed Verified) m a -> WithAuthorizer m a)
-> (m a -> ReaderT (Biscuit OpenOrSealed Verified) m a)
-> m a
-> WithAuthorizer m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> ReaderT (Biscuit OpenOrSealed Verified) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift
noAuthorizer :: Applicative m
=> ReaderT (Biscuit OpenOrSealed Verified) m a
-> WithAuthorizer m a
noAuthorizer :: ReaderT (Biscuit OpenOrSealed Verified) m a -> WithAuthorizer m a
noAuthorizer = Authorizer
-> ReaderT (Biscuit OpenOrSealed Verified) m a
-> WithAuthorizer m a
forall (m :: * -> *) a.
Applicative m =>
Authorizer
-> ReaderT (Biscuit OpenOrSealed Verified) m a
-> WithAuthorizer m a
withAuthorizer Authorizer
forall a. Monoid a => a
mempty
noAuthorizer_ :: Monad m => m a -> WithAuthorizer m a
noAuthorizer_ :: m a -> WithAuthorizer m a
noAuthorizer_ = ReaderT (Biscuit OpenOrSealed Verified) m a -> WithAuthorizer m a
forall (m :: * -> *) a.
Applicative m =>
ReaderT (Biscuit OpenOrSealed Verified) m a -> WithAuthorizer m a
noAuthorizer (ReaderT (Biscuit OpenOrSealed Verified) m a -> WithAuthorizer m a)
-> (m a -> ReaderT (Biscuit OpenOrSealed Verified) m a)
-> m a
-> WithAuthorizer m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> ReaderT (Biscuit OpenOrSealed Verified) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift
extractBiscuit :: PublicKey
-> Request
-> Either String (Biscuit OpenOrSealed Verified)
PublicKey
pk Request
req = do
let note :: a -> Maybe b -> Either a b
note a
e = Either a b -> (b -> Either a b) -> Maybe b -> Either a b
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (a -> Either a b
forall a b. a -> Either a b
Left a
e) b -> Either a b
forall a b. b -> Either a b
Right
ByteString
authHeader <- String -> Maybe ByteString -> Either String ByteString
forall a b. a -> Maybe b -> Either a b
note String
"Missing Authorization header" (Maybe ByteString -> Either String ByteString)
-> ([(HeaderName, ByteString)] -> Maybe ByteString)
-> [(HeaderName, ByteString)]
-> Either String ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HeaderName -> [(HeaderName, ByteString)] -> Maybe ByteString
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup HeaderName
"Authorization" ([(HeaderName, ByteString)] -> Either String ByteString)
-> [(HeaderName, ByteString)] -> Either String ByteString
forall a b. (a -> b) -> a -> b
$ Request -> [(HeaderName, ByteString)]
requestHeaders Request
req
ByteString
b64Token <- String -> Maybe ByteString -> Either String ByteString
forall a b. a -> Maybe b -> Either a b
note String
"Not a Bearer token" (Maybe ByteString -> Either String ByteString)
-> Maybe ByteString -> Either String ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> Maybe ByteString
BS.stripPrefix ByteString
"Bearer " ByteString
authHeader
(ParseError -> String)
-> Either ParseError (Biscuit OpenOrSealed Verified)
-> Either String (Biscuit OpenOrSealed Verified)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (String -> ParseError -> String
forall a b. a -> b -> a
const String
"Not a B64-encoded biscuit") (Either ParseError (Biscuit OpenOrSealed Verified)
-> Either String (Biscuit OpenOrSealed Verified))
-> Either ParseError (Biscuit OpenOrSealed Verified)
-> Either String (Biscuit OpenOrSealed Verified)
forall a b. (a -> b) -> a -> b
$ PublicKey
-> ByteString -> Either ParseError (Biscuit OpenOrSealed Verified)
parseB64 PublicKey
pk ByteString
b64Token
authHandler :: PublicKey
-> AuthHandler Request (Biscuit OpenOrSealed Verified)
authHandler :: PublicKey -> AuthHandler Request (Biscuit OpenOrSealed Verified)
authHandler PublicKey
publicKey = (Request -> Handler (Biscuit OpenOrSealed Verified))
-> AuthHandler Request (Biscuit OpenOrSealed Verified)
forall r usr. (r -> Handler usr) -> AuthHandler r usr
mkAuthHandler Request -> Handler (Biscuit OpenOrSealed Verified)
handler
where
authError :: String -> ServerError
authError String
s = ServerError
err401 { errBody :: ByteString
errBody = ByteString -> ByteString
LBS.fromStrict (String -> ByteString
C8.pack String
s) }
orError :: Either String a -> Handler a
orError = (String -> Handler a)
-> (a -> Handler a) -> Either String a -> Handler a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (ServerError -> Handler a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (ServerError -> Handler a)
-> (String -> ServerError) -> String -> Handler a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ServerError
authError) a -> Handler a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
handler :: Request -> Handler (Biscuit OpenOrSealed Verified)
handler Request
req =
Either String (Biscuit OpenOrSealed Verified)
-> Handler (Biscuit OpenOrSealed Verified)
forall a. Either String a -> Handler a
orError (Either String (Biscuit OpenOrSealed Verified)
-> Handler (Biscuit OpenOrSealed Verified))
-> Either String (Biscuit OpenOrSealed Verified)
-> Handler (Biscuit OpenOrSealed Verified)
forall a b. (a -> b) -> a -> b
$ PublicKey
-> Request -> Either String (Biscuit OpenOrSealed Verified)
extractBiscuit PublicKey
publicKey Request
req
genBiscuitCtx :: PublicKey
-> Context '[AuthHandler Request (Biscuit OpenOrSealed Verified)]
genBiscuitCtx :: PublicKey
-> Context '[AuthHandler Request (Biscuit OpenOrSealed Verified)]
genBiscuitCtx PublicKey
pk = PublicKey -> AuthHandler Request (Biscuit OpenOrSealed Verified)
authHandler PublicKey
pk AuthHandler Request (Biscuit OpenOrSealed Verified)
-> Context '[]
-> Context '[AuthHandler Request (Biscuit OpenOrSealed Verified)]
forall x (xs :: [*]). x -> Context xs -> Context (x : xs)
:. Context '[]
EmptyContext
checkBiscuit :: (MonadIO m, MonadError ServerError m)
=> Biscuit OpenOrSealed Verified
-> Authorizer
-> m a
-> m a
checkBiscuit :: Biscuit OpenOrSealed Verified -> Authorizer -> m a -> m a
checkBiscuit Biscuit OpenOrSealed Verified
vb Authorizer
v m a
h = do
Either ExecutionError AuthorizationSuccess
res <- IO (Either ExecutionError AuthorizationSuccess)
-> m (Either ExecutionError AuthorizationSuccess)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Either ExecutionError AuthorizationSuccess)
-> m (Either ExecutionError AuthorizationSuccess))
-> IO (Either ExecutionError AuthorizationSuccess)
-> m (Either ExecutionError AuthorizationSuccess)
forall a b. (a -> b) -> a -> b
$ Biscuit OpenOrSealed Verified
-> Authorizer -> IO (Either ExecutionError AuthorizationSuccess)
forall proof.
Biscuit proof Verified
-> Authorizer -> IO (Either ExecutionError AuthorizationSuccess)
authorizeBiscuit Biscuit OpenOrSealed Verified
vb Authorizer
v
case Either ExecutionError AuthorizationSuccess
res of
Left ExecutionError
e -> do IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ ExecutionError -> IO ()
forall a. Show a => a -> IO ()
print ExecutionError
e
ServerError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (ServerError -> m a) -> ServerError -> m a
forall a b. (a -> b) -> a -> b
$ ServerError
err401 { errBody :: ByteString
errBody = ByteString
"Biscuit failed checks" }
Right AuthorizationSuccess
_ -> m a
h
checkBiscuitM :: (MonadIO m, MonadError ServerError m)
=> Biscuit OpenOrSealed Verified
-> m Authorizer
-> m a
-> m a
checkBiscuitM :: Biscuit OpenOrSealed Verified -> m Authorizer -> m a -> m a
checkBiscuitM Biscuit OpenOrSealed Verified
vb m Authorizer
mv m a
h = do
Authorizer
v <- m Authorizer
mv
Either ExecutionError AuthorizationSuccess
res <- IO (Either ExecutionError AuthorizationSuccess)
-> m (Either ExecutionError AuthorizationSuccess)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Either ExecutionError AuthorizationSuccess)
-> m (Either ExecutionError AuthorizationSuccess))
-> IO (Either ExecutionError AuthorizationSuccess)
-> m (Either ExecutionError AuthorizationSuccess)
forall a b. (a -> b) -> a -> b
$ Biscuit OpenOrSealed Verified
-> Authorizer -> IO (Either ExecutionError AuthorizationSuccess)
forall proof.
Biscuit proof Verified
-> Authorizer -> IO (Either ExecutionError AuthorizationSuccess)
authorizeBiscuit Biscuit OpenOrSealed Verified
vb Authorizer
v
case Either ExecutionError AuthorizationSuccess
res of
Left ExecutionError
e -> do IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ ExecutionError -> IO ()
forall a. Show a => a -> IO ()
print ExecutionError
e
ServerError -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (ServerError -> m a) -> ServerError -> m a
forall a b. (a -> b) -> a -> b
$ ServerError
err401 { errBody :: ByteString
errBody = ByteString
"Biscuit failed checks" }
Right AuthorizationSuccess
_ -> m a
h
handleBiscuit :: (MonadIO m, MonadError ServerError m)
=> Biscuit OpenOrSealed Verified
-> WithAuthorizer m a
-> m a
handleBiscuit :: Biscuit OpenOrSealed Verified -> WithAuthorizer m a -> m a
handleBiscuit Biscuit OpenOrSealed Verified
b WithAuthorizer{m Authorizer
authorizer_ :: m Authorizer
authorizer_ :: forall (m :: * -> *) a. WithAuthorizer m a -> m Authorizer
authorizer_, ReaderT (Biscuit OpenOrSealed Verified) m a
handler_ :: ReaderT (Biscuit OpenOrSealed Verified) m a
handler_ :: forall (m :: * -> *) a.
WithAuthorizer m a -> ReaderT (Biscuit OpenOrSealed Verified) m a
handler_} =
let h :: m a
h = ReaderT (Biscuit OpenOrSealed Verified) m a
-> Biscuit OpenOrSealed Verified -> m a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT (Biscuit OpenOrSealed Verified) m a
handler_ Biscuit OpenOrSealed Verified
b
in Biscuit OpenOrSealed Verified -> m Authorizer -> m a -> m a
forall (m :: * -> *) a.
(MonadIO m, MonadError ServerError m) =>
Biscuit OpenOrSealed Verified -> m Authorizer -> m a -> m a
checkBiscuitM Biscuit OpenOrSealed Verified
b m Authorizer
authorizer_ m a
h