{-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} module Main (main) where import Auth.Biscuit import Data.Maybe (fromJust) import Data.Text (Text) import Data.Text.Encoding (decodeUtf8) import Test.Hspec import AppWithVerifier (app, call1, call2, call3) import ClientHelpers (runC, withApp) main :: IO () main = do keypair <- fromPrivateKey appPrivateKey let appPk = publicKey keypair adminB <- toText <$> mkAdminBiscuit keypair anonB <- toText <$> mkAnonBiscuit keypair e1 <- toText <$> mkE1Biscuit keypair e21 <- toText <$> mkE2Biscuit 1 keypair e22 <- toText <$> mkE2Biscuit 2 keypair print adminB hspec $ around (withApp $ app appPk) $ describe "Biscuit-protected servant app" $ do it "Priority rules should apply everywhere" $ \port -> do runC port (call1 adminB) `shouldReturn` Right 1 runC port (call2 adminB 1) `shouldReturn` Right 2 runC port (call3 adminB) `shouldReturn` Right 3 it "Fallback rules should only apply after inner rules" $ \port -> do runC port (call1 anonB) `shouldReturn` Right 1 runC port (call2 anonB 1) `shouldReturn` Right 2 runC port (call3 anonB) `shouldReturn` Left (Just "Biscuit failed checks") it "Endpoint rules should be matched after priority rules and before fallback rules" $ \port -> do runC port (call1 e1) `shouldReturn` Right 1 runC port (call2 e21 1) `shouldReturn` Right 2 runC port (call2 e22 1) `shouldReturn` Left (Just "Biscuit failed checks") runC port (call3 anonB) `shouldReturn` Left (Just "Biscuit failed checks") appPrivateKey :: PrivateKey appPrivateKey = fromJust . parsePrivateKeyHex $ "c2b7507af4f849fd028d0f7e90b04a4e74d9727b358fca18b65beffd86c47209" toText :: Biscuit -> Text toText = decodeUtf8 . serializeB64 mkAdminBiscuit :: Keypair -> IO Biscuit mkAdminBiscuit kp = mkBiscuit kp [block|right(#authority, #admin);|] mkAnonBiscuit :: Keypair -> IO Biscuit mkAnonBiscuit kp = mkBiscuit kp [block|right(#authority, #anon);|] mkE1Biscuit :: Keypair -> IO Biscuit mkE1Biscuit kp = mkBiscuit kp [block|right(#authority, #one);|] mkE2Biscuit :: Int -> Keypair -> IO Biscuit mkE2Biscuit v kp = mkBiscuit kp [block|right(#authority, #two, ${v});|]