diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Crypto/Macaroon/Verifier.hs | 73 |
1 files changed, 22 insertions, 51 deletions
diff --git a/src/Crypto/Macaroon/Verifier.hs b/src/Crypto/Macaroon/Verifier.hs index 02cb448..713a971 100644 --- a/src/Crypto/Macaroon/Verifier.hs +++ b/src/Crypto/Macaroon/Verifier.hs | |||
@@ -1,5 +1,5 @@ | |||
1 | {-# LANGUAGE OverloadedStrings #-} | 1 | {-# LANGUAGE OverloadedStrings #-} |
2 | {-# LANGUAGE RankNTypes #-} | 2 | {-# LANGUAGE RankNTypes #-} |
3 | {-| | 3 | {-| |
4 | Module : Crypto.Macaroon.Verifier | 4 | Module : Crypto.Macaroon.Verifier |
5 | Copyright : (c) 2015 Julien Tanguy | 5 | Copyright : (c) 2015 Julien Tanguy |
@@ -13,79 +13,50 @@ Portability : portable | |||
13 | 13 | ||
14 | -} | 14 | -} |
15 | module Crypto.Macaroon.Verifier ( | 15 | module Crypto.Macaroon.Verifier ( |
16 | Verified(..) | 16 | Verifier |
17 | , CaveatVerifier | ||
18 | , (<???>) | ||
19 | , verifyMacaroon | 17 | , verifyMacaroon |
20 | , verifySig | 18 | , verifySig |
21 | , verifyExact | 19 | -- , verifyExact |
22 | , verifyFun | 20 | -- , verifyFun |
23 | , module Data.Attoparsec.ByteString.Char8 | 21 | , module Data.Attoparsec.ByteString.Char8 |
24 | , verifyCavs | 22 | , verifyCavs |
25 | ) where | 23 | ) where |
26 | 24 | ||
27 | 25 | ||
28 | import Crypto.Hash | 26 | import Crypto.Hash |
27 | import Data.Attoparsec.ByteString | ||
28 | import Data.Attoparsec.ByteString.Char8 | ||
29 | import Data.Bool | 29 | import Data.Bool |
30 | import qualified Data.ByteString as BS | ||
31 | import Data.Byteable | 30 | import Data.Byteable |
31 | import qualified Data.ByteString as BS | ||
32 | import Data.Either | ||
33 | import Data.Either.Validation | ||
32 | import Data.Foldable | 34 | import Data.Foldable |
33 | import Data.Function | 35 | import Data.Function |
34 | import Data.Maybe | 36 | import Data.Maybe |
35 | import Data.Traversable | 37 | import Data.Traversable |
36 | import Data.Attoparsec.ByteString | ||
37 | import Data.Attoparsec.ByteString.Char8 | ||
38 | 38 | ||
39 | import Crypto.Macaroon.Internal | 39 | import Crypto.Macaroon.Internal |
40 | 40 | ||
41 | type Verifier = Caveat -> Maybe (Either String Caveat) | ||
41 | 42 | ||
42 | -- | Opaque datatype for now. Might need more explicit errors | 43 | verifySig :: Key -> Macaroon -> Either String Macaroon |
43 | data Verified = Ok | Failed deriving (Show,Eq) | 44 | verifySig k m = bool (Left "Signatures do not match") (Right m) $ |
44 | |||
45 | instance Monoid Verified where | ||
46 | mempty = Ok | ||
47 | mappend Ok Ok = Ok | ||
48 | mappend _ _ = Failed | ||
49 | |||
50 | |||
51 | data CaveatVerifier = CV { vFun :: Caveat -> Maybe Verified , helpText :: String} | ||
52 | |||
53 | instance Eq CaveatVerifier where | ||
54 | (==) = (==) `on` helpText | ||
55 | |||
56 | instance Show CaveatVerifier where | ||
57 | show = helpText | ||
58 | |||
59 | (<???>) :: (Caveat -> Maybe Verified) -> String -> CaveatVerifier | ||
60 | f <???> t = CV f t | ||
61 | |||
62 | verifySig :: Key -> Macaroon -> Verified | ||
63 | verifySig k m = bool Failed Ok $ | ||
64 | signature m == foldl' hash (toBytes (hmac derivedKey (identifier m) :: HMAC SHA256)) (caveats m) | 45 | signature m == foldl' hash (toBytes (hmac derivedKey (identifier m) :: HMAC SHA256)) (caveats m) |
65 | where | 46 | where |
66 | hash s c = toBytes (hmac s (vid c `BS.append` cid c) :: HMAC SHA256) | 47 | hash s c = toBytes (hmac s (vid c `BS.append` cid c) :: HMAC SHA256) |
67 | derivedKey = toBytes (hmac "macaroons-key-generator" k :: HMAC SHA256) | 48 | derivedKey = toBytes (hmac "macaroons-key-generator" k :: HMAC SHA256) |
68 | 49 | ||
69 | verifyMacaroon :: Key -> [CaveatVerifier] -> Macaroon -> Verified | 50 | verifyMacaroon :: Key -> [Verifier] -> Macaroon -> Either String Macaroon |
70 | verifyMacaroon secret verifiers m = verifySig secret m `mappend` verifyCavs verifiers m | 51 | verifyMacaroon secret verifiers m = verifySig secret m >>= verifyCavs verifiers |
71 | |||
72 | 52 | ||
73 | verifyCavs :: [CaveatVerifier] -> Macaroon -> Verified | 53 | verifyCavs :: [Verifier] -> Macaroon -> Either String Macaroon |
74 | verifyCavs verifiers m = foldMap (\c -> fromMaybe Failed $ foldMap (($ c) . vFun) verifiers) (caveats m) | 54 | verifyCavs verifiers m = case partitionEithers verifiedCaveats of |
55 | ([],_) -> Right m | ||
56 | (errs,_) -> Left (mconcat errs) | ||
57 | where | ||
58 | verifiedCaveats = map (\c -> defaultFail c $ foldMap (fmap eitherToValidation . ($c)) verifiers) $ caveats m | ||
59 | defaultFail c = maybe (Left ("No validation for this caveat: " ++ show c)) validationToEither | ||
75 | 60 | ||
76 | verifyExact :: (Eq a) => Key -> a -> Parser a -> Caveat -> Maybe Verified | ||
77 | verifyExact k expected = verifyFun k (expected ==) | ||
78 | 61 | ||
79 | verifyFun :: Key -> (a -> Bool) -> Parser a -> Caveat -> Maybe Verified | 62 | -- TODO: define API |
80 | verifyFun key f parser cav = if key `BS.isPrefixOf` cid cav then | ||
81 | case parseOnly kvparser (cid cav) of | ||
82 | Right v -> (bool Failed Ok . f) <$> Just v | ||
83 | Left _ -> Just Failed | ||
84 | else Nothing | ||
85 | where | ||
86 | kvparser = do | ||
87 | key <- string key | ||
88 | skipSpace | ||
89 | string "=" | ||
90 | skipSpace | ||
91 | parser <* endOfInput | ||