Copyright | © Clément Delafargue 2021 |
---|---|
License | MIT |
Maintainer | clement@delafargue.name |
Safe Haskell | Safe-Inferred |
Language | Haskell2010 |
Haskell implementation for the Biscuit token.
Synopsis
- newSecret :: IO SecretKey
- toPublic :: SecretKey -> PublicKey
- data SecretKey
- data PublicKey
- serializeSecretKeyHex :: SecretKey -> ByteString
- serializePublicKeyHex :: PublicKey -> ByteString
- parseSecretKeyHex :: ByteString -> Maybe SecretKey
- parsePublicKeyHex :: ByteString -> Maybe PublicKey
- serializeSecretKey :: SecretKey -> ByteString
- serializePublicKey :: PublicKey -> ByteString
- parseSecretKey :: ByteString -> Maybe SecretKey
- parsePublicKey :: ByteString -> Maybe PublicKey
- mkBiscuit :: SecretKey -> Block -> IO (Biscuit Open Verified)
- mkBiscuitWith :: Maybe Int -> SecretKey -> Block -> IO (Biscuit Open Verified)
- block :: QuasiQuoter
- blockContext :: Text -> Block
- data Biscuit proof check
- data OpenOrSealed
- data Open
- data Sealed
- data Verified
- data Unverified
- class BiscuitProof a
- type Block = Block' 'Repr 'Representation
- parseB64 :: PublicKey -> ByteString -> Either ParseError (Biscuit OpenOrSealed Verified)
- parse :: PublicKey -> ByteString -> Either ParseError (Biscuit OpenOrSealed Verified)
- parseWith :: Applicative m => ParserConfig m -> ByteString -> m (Either ParseError (Biscuit OpenOrSealed Verified))
- parseBiscuitUnverified :: ByteString -> Either ParseError (Biscuit OpenOrSealed Unverified)
- checkBiscuitSignatures :: BiscuitProof proof => (Maybe Int -> PublicKey) -> Biscuit proof Unverified -> Either ParseError (Biscuit proof Verified)
- data BiscuitEncoding
- data ParserConfig m = ParserConfig {
- encoding :: BiscuitEncoding
- isRevoked :: Set ByteString -> m Bool
- getPublicKey :: Maybe Int -> PublicKey
- fromRevocationList :: (Applicative m, Foldable t) => t ByteString -> Set ByteString -> m Bool
- serializeB64 :: BiscuitProof p => Biscuit p Verified -> ByteString
- serialize :: BiscuitProof p => Biscuit p Verified -> ByteString
- fromHex :: MonadFail m => ByteString -> m ByteString
- addBlock :: Block -> Biscuit Open check -> IO (Biscuit Open check)
- addSignedBlock :: SecretKey -> Block -> Biscuit Open check -> IO (Biscuit Open check)
- mkThirdPartyBlockReq :: Biscuit proof check -> ByteString
- mkThirdPartyBlockReqB64 :: Biscuit Open c -> ByteString
- mkThirdPartyBlock :: SecretKey -> ByteString -> Block -> Either String ByteString
- mkThirdPartyBlockB64 :: SecretKey -> ByteString -> Block -> Either String ByteString
- applyThirdPartyBlock :: Biscuit Open check -> ByteString -> Either String (IO (Biscuit Open check))
- applyThirdPartyBlockB64 :: Biscuit Open check -> ByteString -> Either String (IO (Biscuit Open check))
- seal :: Biscuit Open check -> Biscuit Sealed check
- fromOpen :: Biscuit Open check -> Biscuit OpenOrSealed check
- fromSealed :: Biscuit Sealed check -> Biscuit OpenOrSealed check
- asOpen :: Biscuit OpenOrSealed check -> Maybe (Biscuit Open check)
- asSealed :: Biscuit OpenOrSealed check -> Maybe (Biscuit Sealed check)
- authorizer :: QuasiQuoter
- type Authorizer = Authorizer' 'Repr 'Representation
- authorizeBiscuit :: Biscuit proof Verified -> Authorizer -> IO (Either ExecutionError (AuthorizedBiscuit proof))
- authorizeBiscuitWithLimits :: Limits -> Biscuit proof Verified -> Authorizer -> IO (Either ExecutionError (AuthorizedBiscuit proof))
- data Limits = Limits {
- maxFacts :: Int
- maxIterations :: Int
- maxTime :: Int
- allowRegexes :: Bool
- defaultLimits :: Limits
- data ParseError
- data ExecutionError
- data AuthorizedBiscuit p = AuthorizedBiscuit {}
- data AuthorizationSuccess = AuthorizationSuccess {}
- data MatchedQuery = MatchedQuery {
- matchedQuery :: Query
- bindings :: Set Bindings
- getBindings :: AuthorizationSuccess -> Set Bindings
- class ToTerm t inSet pof where
- toTerm :: t -> Term' inSet pof 'Representation
- class FromValue t where
- type Term = Term' 'NotWithinSet 'InPredicate 'Representation
- data Term' (inSet :: IsWithinSet) (pof :: PredicateOrFact) (ctx :: DatalogContext)
- queryAuthorizerFacts :: AuthorizedBiscuit p -> Query -> Set Bindings
- queryRawBiscuitFacts :: Biscuit openOrSealed check -> Query -> Set Bindings
- getVariableValues :: (Ord t, FromValue t) => Set Bindings -> Text -> Set t
- getSingleVariableValue :: (Ord t, FromValue t) => Set Bindings -> Text -> Maybe t
- query :: QuasiQuoter
- getRevocationIds :: Biscuit proof check -> NonEmpty ByteString
- getVerifiedBiscuitPublicKey :: Biscuit a Verified -> PublicKey
The biscuit auth token
Biscuit is a bearer token,
allowing offline attenuation (meaning that anyone having a token can craft a new, more
restricted token),
and PublicKey
verification. Token rights and attenuation are expressed using a logic
language, derived from datalog. Such a language can describe facts (things we know
about the world), rules (describing how to derive new facts from existing ones) and checks
(ensuring that facts hold). Facts and checks let you describe access control rules, while
rules make them modular. Authorizer policies lets the verifying party ensure that a
provided biscuit grants access to the required operations.
Here's how to create a biscuit token:
-- Biscuit Open Verified means the token has valid signatures -- and is open to further restriction buildToken :: Keypair -> IO (Biscuit Open Verified) buildToken keypair = -- the logic language has its own syntax, which can be typed directly in haskell -- source code thanks to QuasiQuotes. The datalog snippets are parsed at compile -- time, so a datalog error results in a compilation error, not a runtime error mkBiscuit keypair [block| // the two first lines describe facts: // the token holder is identified as `user_1234` user("user_1234"); // the token holder is granted access to resource `file1` resource("file1"); // this last line defines a restriction: properties that need // to be verified for the token to be verified: // the token can only be used before a specified date check if time($time), $time < 2021-05-08T00:00:00Z; |]
Here's how to attenuate a biscuit token:
restrictToken :: Biscuit Open Verified -> IO Biscuit Open Verified restrictToken = addBlock [block| // restrict the token to local use only check if user_ip_address("127.0.0.1"); |]
To verify a biscuit token, we need two things:
- a public key, that will let us verify the token has been emitted by a trusted authority
- an authorizer, that will make sure all the checks declared in the token are fulfilled, as well as providing its own checks, and policies which decide if the token is verified or not
Here's how to verify a base64-serialized biscuit token:
verifyToken :: PublicKey -> ByteString -> IO Bool verifyToken publicKey token = do -- complete parsing is only attempted if signatures can be verified, -- that's the reason why 'parseB64' takes a public key as a parameter parseResult <- parseB64 publicKey token case parseResult of Left e -> print e $> False Right biscuit -> do now <- getCurrentTime let authorizer' = [authorizer| // the datalog snippets can reference haskell variables // with the {variableName} syntax time({now}); // policies are tried in order. The first matching policy // will decide if the token is valid or not. If no policies // match, the token will fail validation allow if resource("file1"); |] result <- authorizeBiscuit biscuit authorizer' case result of Left e -> print e $> False Right _ -> pure True
Creating keypairs
Biscuits rely on public key cryptography: biscuits are signed with a secret key only known to the party which emits it. Verifying a biscuit, on the other hand, can be done with a public key that can be widely distributed. A private key and its corresponding public key is called a keypair, but since a public key can be deterministically computed from a private key, owning a private key is the same as owning a keypair.
Instances
Parsing and serializing keypairs
serializeSecretKeyHex :: SecretKey -> ByteString Source #
Serialize a SecretKey
to a hex-encoded bytestring
serializePublicKeyHex :: PublicKey -> ByteString Source #
Serialize a PublicKey
to a hex-encoded bytestring
parseSecretKeyHex :: ByteString -> Maybe SecretKey Source #
Read a SecretKey
from an hex bytestring
parsePublicKeyHex :: ByteString -> Maybe PublicKey Source #
Read a PublicKey
from an hex bytestring
serializeSecretKey :: SecretKey -> ByteString Source #
Serialize a SecretKey
to raw bytes, without any encoding
serializePublicKey :: PublicKey -> ByteString Source #
Serialize a PublicKey
to raw bytes, without any encoding
parseSecretKey :: ByteString -> Maybe SecretKey Source #
Read a SecretKey
from raw bytes
parsePublicKey :: ByteString -> Maybe PublicKey Source #
Read a PublicKey
from raw bytes
Creating a biscuit
The core of a biscuit is its authority block. This block declares facts and rules and is signed by its creator with a secret key. In addition to this trusted, authority block, a biscuit may carry extra blocks that can only restrict what it can do. By default, biscuits can be restricted, but it's possible to seal a biscuit and prevent further modifications.
Blocks are defined with a logic language (datalog) that can be used directly from haskell
with the QuasiQuotes
extension.
mkBiscuit :: SecretKey -> Block -> IO (Biscuit Open Verified) Source #
Create a new biscuit with the provided authority block. Such a biscuit is Open
to
further attenuation.
mkBiscuitWith :: Maybe Int -> SecretKey -> Block -> IO (Biscuit Open Verified) Source #
Create a new biscuit with the provided authority block and root key id. Such a biscuit is Open
to
further attenuation.
block :: QuasiQuoter Source #
Compile-time parser for a block expression, intended to be used with the
QuasiQuotes
extension.
A typical use of block
looks like this:
let fileName = "data.pdf" in [block| // datalog can reference haskell variables with {variableName} resource({fileName}); rule($variable) <- fact($value), other_fact($value); check if operation("read"); |]
blockContext :: Text -> Block Source #
Build a block containing an explicit freeform context value.
The context of a block can't be parsed from datalog,
so you'll need an explicit call to blockContext
to add it
[block|check if time($t), $t < 2021-01-01;|] <> blockContext "ttl-check"
data Biscuit proof check Source #
A parsed biscuit. The proof
type param can be one of Open
, Sealed
or OpenOrSealed
.
It describes whether a biscuit is open to further attenuation, or sealed and not modifyable
further.
The check
type param can be either Verified
or Unverified
and keeps track of whether
the blocks signatures (and final proof) have been verified with a given root PublicKey
.
The constructor is not exposed in order to ensure that Biscuit
values can only be created
by trusted code paths.
data OpenOrSealed Source #
This datatype represents the final proof of a biscuit, which can be either open or sealed. This is the typical state of a biscuit that's been parsed.
Instances
Show OpenOrSealed Source # | |
Defined in Auth.Biscuit.Token showsPrec :: Int -> OpenOrSealed -> ShowS # show :: OpenOrSealed -> String # showList :: [OpenOrSealed] -> ShowS # | |
BiscuitProof OpenOrSealed Source # | |
Defined in Auth.Biscuit.Token | |
Eq OpenOrSealed Source # | |
Defined in Auth.Biscuit.Token (==) :: OpenOrSealed -> OpenOrSealed -> Bool # (/=) :: OpenOrSealed -> OpenOrSealed -> Bool # |
This datatype represents the final proof of a biscuit statically known to be open (capable of being attenuated further). In that case the proof is a secret key that can be used to sign a new block.
Instances
Show Open Source # | |
BiscuitProof Open Source # | |
Defined in Auth.Biscuit.Token toPossibleProofs :: Open -> OpenOrSealed Source # | |
Eq Open Source # | |
This datatype represents the final proof of a biscuit statically known to be sealed (not capable of being attenuated further). In that case the proof is a signature proving that the party who sealed the token did know the last secret key.
Proof that a biscuit had its signatures verified with the carried root PublicKey
data Unverified Source #
Marker that a biscuit was parsed without having its signatures verified. Such a biscuit cannot be trusted yet.
Instances
Show Unverified Source # | |
Defined in Auth.Biscuit.Token showsPrec :: Int -> Unverified -> ShowS # show :: Unverified -> String # showList :: [Unverified] -> ShowS # | |
Eq Unverified Source # | |
Defined in Auth.Biscuit.Token (==) :: Unverified -> Unverified -> Bool # (/=) :: Unverified -> Unverified -> Bool # |
class BiscuitProof a Source #
This class allows functions working on both open and sealed biscuits to accept
indifferently OpenOrSealed
, Open
or Sealed
biscuits. It has no laws, it only
projects Open
and Sealed
to the general OpenOrSealed
case.
Instances
BiscuitProof Open Source # | |
Defined in Auth.Biscuit.Token toPossibleProofs :: Open -> OpenOrSealed Source # | |
BiscuitProof OpenOrSealed Source # | |
Defined in Auth.Biscuit.Token | |
BiscuitProof Sealed Source # | |
Defined in Auth.Biscuit.Token |
type Block = Block' 'Repr 'Representation Source #
A biscuit block, containing facts, rules and checks.
Block
has a Monoid
instance, which is the expected way
to build composite blocks (eg if you need to generate a list of facts):
-- build a block from multiple variables v1, v2, v3 [block| value({v1}); |] <> [block| value({v2}); |] <> [block| value({v3}); |]
Parsing and serializing biscuits
parseB64 :: PublicKey -> ByteString -> Either ParseError (Biscuit OpenOrSealed Verified) Source #
Parse a biscuit from a URL-compatible base 64 encoded bytestring
parse :: PublicKey -> ByteString -> Either ParseError (Biscuit OpenOrSealed Verified) Source #
Parse a biscuit from a raw bytestring. If you want to parse
from a URL-compatible base 64 bytestring, consider using parseB64
instead.
The biscuit signature is verified with the provided PublicKey
before
completely decoding blocks
The revocation ids are not verified before completely decoding blocks.
If you need to check revocation ids before decoding blocks, use parseWith
(or parseB64With
instead).
parseWith :: Applicative m => ParserConfig m -> ByteString -> m (Either ParseError (Biscuit OpenOrSealed Verified)) Source #
parseBiscuitUnverified :: ByteString -> Either ParseError (Biscuit OpenOrSealed Unverified) Source #
Parse a biscuit without performing any signatures check. This function is intended to
provide tooling (eg adding a block, or inspecting a biscuit) without having to verify
its signatures. Running an Authorizer
is not possible without checking signatures.
checkBiscuitSignatures
allows a delayed signature check. For normal auth workflows,
please use parseWith
(or parse
, or parseB64
) instead, as they check signatures
before completely parsing the biscuit.
checkBiscuitSignatures :: BiscuitProof proof => (Maybe Int -> PublicKey) -> Biscuit proof Unverified -> Either ParseError (Biscuit proof Verified) Source #
Check the signatures (and final proof) of an already parsed biscuit. These checks normally
happen during the parsing phase, but can be delayed (or even ignored) in some cases. This
fuction allows to turn a Unverified
Biscuit
into a Verified
one after it has been parsed
with parseBiscuitUnverified
.
data BiscuitEncoding Source #
Biscuits can be transmitted as raw bytes, or as base64-encoded text. This datatype lets the parser know about the expected encoding.
data ParserConfig m Source #
Parsing a biscuit involves various steps. This data type allows configuring those steps.
ParserConfig | |
|
fromRevocationList :: (Applicative m, Foldable t) => t ByteString -> Set ByteString -> m Bool Source #
Helper for building a revocation check from a static list, suitable for use with
parseWith
and ParserConfig
.
serializeB64 :: BiscuitProof p => Biscuit p Verified -> ByteString Source #
Serialize a biscuit to URL-compatible base 64, as recommended by the spec
serialize :: BiscuitProof p => Biscuit p Verified -> ByteString Source #
Serialize a biscuit to a binary format. If you intend to send
the biscuit over a text channel, consider using serializeB64
instead
fromHex :: MonadFail m => ByteString -> m ByteString Source #
Decode a base16-encoded bytestring, reporting errors via MonadFail
Attenuating biscuits
By default, biscuits can be attenuated. It means that any party that holds a biscuit can craft a new biscuit with fewer rights. A common example is taking a long-lived biscuit and adding a short TTL right before sending it over the wire.
Third-party blocks
Regular blocks can be added by anyone and as such can only attenuate a token: the facts they carry are not visible outside themselves, only their checks are evaluated.
Third-party blocks lift this limitation by carrying an extra signature, crafted with a dedicated keypair. This way, the token authorizer (as well as blocks themselves) can opt-in to trust facts coming from third-party blocks signed with specific keypairs.
For instance, adding `check if group("admin") trusting {publicKey};` to a token will make it usable only if it carries a third party-block signed by the corresponding keypair, and carrying a `group("admin")` fact.
Since it is not desirable to share the token with the external entity providing the third-party block, a request mechanism is available:
- the token holder generates a third-party block request from the token (it contains technical
information needed to generate a third-party block) with
mkThirdPartyBlockReq
; - the token holder forwards this request to the external entity;
- the external entity uses this request, a
Block
value, and aSecretKey
to generate a third-party block, withmkThirdPartyBlock
; - the external entity sends this block back to the token holder;
- the token holder can now add the block to the token with
applyThirdPartyBlock
.
In some cases, the party holding the token is also the one who's adding the third-party block. It
is then possible to directly use addSignedBlock
to append a third-party block to the token without
having to go through generating a third-party block request.
addSignedBlock :: SecretKey -> Block -> Biscuit Open check -> IO (Biscuit Open check) Source #
Directly append a third-party block to a token. Please use
mkThirdPartyBlockReq
, mkThirdPartyBlock
and applyThirdPartyBlock
instead if the party signing the block cannot have access to the token.
mkThirdPartyBlockReq :: Biscuit proof check -> ByteString Source #
Generate a third-party block request. It can be used in
conjunction with mkThirdPartyBlock
to generate a
third-party block, which can be then appended to a token with
applyThirdPartyBlock
.
mkThirdPartyBlockReqB64 :: Biscuit Open c -> ByteString Source #
Generate a base64-encoded third-party block request. It can be used in
conjunction with mkThirdPartyBlockB64
to generate a base64-encoded
third-party block, which can be then appended to a token with
applyThirdPartyBlockB64
.
mkThirdPartyBlock :: SecretKey -> ByteString -> Block -> Either String ByteString Source #
Given a third-party block request, generate a third-party block,
which can be then appended to a token with applyThirdPartyBlock
.
mkThirdPartyBlockB64 :: SecretKey -> ByteString -> Block -> Either String ByteString Source #
Given a base64-encoded third-party block request, generate a base64-encoded
third-party block, which can be then appended to a token with
applyThirdPartyBlockB64
.
applyThirdPartyBlock :: Biscuit Open check -> ByteString -> Either String (IO (Biscuit Open check)) Source #
Given a base64-encoded third-party block, append it to a token.
applyThirdPartyBlockB64 :: Biscuit Open check -> ByteString -> Either String (IO (Biscuit Open check)) Source #
Given a base64-encoded third-party block, append it to a token.
Sealing biscuits
An Open
biscuit can be turned into a Sealed
one, meaning it won't be possible
to attenuate it further.
mkBiscuit
creates Open
biscuits, while parse
returns an OpenOrSealed
biscuit (since
when you're verifying a biscuit, you're not caring about whether it can be extended further
or not). authorizeBiscuit
does not care whether a biscuit is Open
or Sealed
and can be
used with both. addBlock
and seal
only work with Open
biscuits.
fromOpen :: Biscuit Open check -> Biscuit OpenOrSealed check Source #
Turn a Biscuit
statically known to be Open
into a more generic OpenOrSealed
Biscuit
(essentially forgetting about the fact it's Open
)
fromSealed :: Biscuit Sealed check -> Biscuit OpenOrSealed check Source #
Turn a Biscuit
statically known to be Sealed
into a more generic OpenOrSealed
Biscuit
(essentially forgetting about the fact it's Sealed
)
Verifying a biscuit
Verifying a biscuit requires providing a list of policies (allow or deny), which will decide if the biscuit is accepted. Policies are tried in order, and the first one to match decides whether the biscuit is accepted.
In addition to policies, an authorizer typically provides facts (such as the current time) so that checks and policies can be verified.
The authorizer checks and policies only see the content of the authority (first) block. Extra blocks can only carry restrictions and cannot interfere with the authority facts.
authorizer :: QuasiQuoter Source #
Compile-time parser for an authorizer expression, intended to be used with the
QuasiQuotes
extension.
A typical use of authorizer
looks like this:
do now <- getCurrentTime pure [authorizer| // datalog can reference haskell variables with {variableName} current_time({now}); // authorizers can contain facts, rules and checks like blocks, but // also declare policies. While every check has to pass for a biscuit to // be valid, policies are tried in order. The first one to match decides // if the token is valid or not allow if resource("file1"); deny if true; |]
type Authorizer = Authorizer' 'Repr 'Representation Source #
A biscuit authorizer, containing, facts, rules, checks and policies
authorizeBiscuit :: Biscuit proof Verified -> Authorizer -> IO (Either ExecutionError (AuthorizedBiscuit proof)) Source #
Given a biscuit with a verified signature and an authorizer (a set of facts, rules, checks and policies), verify a biscuit:
- all the checks declared in the biscuit and authorizer must pass
- an allow policy provided by the authorizer has to match (policies are tried in order)
- the datalog computation must happen in an alloted time, with a capped number of generated facts and a capped number of iterations
checks and policies declared in the authorizer only operate on the authority block. Facts declared by extra blocks cannot interfere with previous blocks.
Specific runtime limits can be specified by using authorizeBiscuitWithLimits
. authorizeBiscuit
uses a set of defaults defined in defaultLimits
.
authorizeBiscuitWithLimits :: Limits -> Biscuit proof Verified -> Authorizer -> IO (Either ExecutionError (AuthorizedBiscuit proof)) Source #
Generic version of authorizeBiscuitWithLimits
which takes custom Limits
.
Settings for the executor runtime restrictions.
See defaultLimits
for default values.
Limits | |
|
defaultLimits :: Limits Source #
Default settings for the executor restrictions. - 1000 facts - 100 iterations - 1000μs max - regexes are allowed - facts and rules are allowed in blocks
data ParseError Source #
Errors that can happen when parsing a biscuit. Since complete parsing of a biscuit requires a signature check, an invalid signature check is a parsing error
InvalidHexEncoding | The provided ByteString is not hex-encoded |
InvalidB64Encoding | The provided ByteString is not base64-encoded |
InvalidProtobufSer Bool String | The provided ByteString does not contain properly serialized protobuf values The boolean parameter is True if the error happened on the wrapper, False if it happened on a block |
InvalidProtobuf Bool String | The bytestring was correctly deserialized from protobuf, but the values can't be turned into a proper biscuit The boolean parameter is True if the error happened on the wrapper, False if it happened on a block |
InvalidSignatures | The signatures were invalid |
InvalidProof | The biscuit final proof was invalid |
RevokedBiscuit | The biscuit has been revoked |
Instances
Show ParseError Source # | |
Defined in Auth.Biscuit.Token showsPrec :: Int -> ParseError -> ShowS # show :: ParseError -> String # showList :: [ParseError] -> ShowS # | |
Eq ParseError Source # | |
Defined in Auth.Biscuit.Token (==) :: ParseError -> ParseError -> Bool # (/=) :: ParseError -> ParseError -> Bool # |
data ExecutionError Source #
An error that can happen while running a datalog verification.
The datalog computation itself can be aborted by runtime failsafe
mechanisms, or it can run to completion but fail to fullfil checks
and policies (ResultError
).
Timeout | Verification took too much time |
TooManyFacts | Too many facts were generated during evaluation |
TooManyIterations | Evaluation did not converge in the alloted number of iterations |
InvalidRule | Some rules were malformed: every variable present in their head must appear in their body |
ResultError ResultError | The evaluation ran to completion, but checks and policies were not fulfilled. |
Instances
Show ExecutionError Source # | |
Defined in Auth.Biscuit.Datalog.Executor showsPrec :: Int -> ExecutionError -> ShowS # show :: ExecutionError -> String # showList :: [ExecutionError] -> ShowS # | |
Eq ExecutionError Source # | |
Defined in Auth.Biscuit.Datalog.Executor (==) :: ExecutionError -> ExecutionError -> Bool # (/=) :: ExecutionError -> ExecutionError -> Bool # |
data AuthorizedBiscuit p Source #
The results of authorization, along with the biscuit that was authorized.
Instances
Show p => Show (AuthorizedBiscuit p) Source # | |
Defined in Auth.Biscuit.Token showsPrec :: Int -> AuthorizedBiscuit p -> ShowS # show :: AuthorizedBiscuit p -> String # showList :: [AuthorizedBiscuit p] -> ShowS # | |
Eq p => Eq (AuthorizedBiscuit p) Source # | |
Defined in Auth.Biscuit.Token (==) :: AuthorizedBiscuit p -> AuthorizedBiscuit p -> Bool # (/=) :: AuthorizedBiscuit p -> AuthorizedBiscuit p -> Bool # |
data AuthorizationSuccess Source #
Proof that a biscuit was authorized successfully. In addition to the matched
allow query
, the generated facts are kept around for further querying.
Since only authority facts can be trusted, they are kept separate.
AuthorizationSuccess | |
|
Instances
Show AuthorizationSuccess Source # | |
Defined in Auth.Biscuit.Datalog.ScopedExecutor showsPrec :: Int -> AuthorizationSuccess -> ShowS # show :: AuthorizationSuccess -> String # showList :: [AuthorizationSuccess] -> ShowS # | |
Eq AuthorizationSuccess Source # | |
Defined in Auth.Biscuit.Datalog.ScopedExecutor (==) :: AuthorizationSuccess -> AuthorizationSuccess -> Bool # (/=) :: AuthorizationSuccess -> AuthorizationSuccess -> Bool # |
data MatchedQuery Source #
A datalog query that was matched, along with the values that matched
Instances
Show MatchedQuery Source # | |
Defined in Auth.Biscuit.Datalog.Executor showsPrec :: Int -> MatchedQuery -> ShowS # show :: MatchedQuery -> String # showList :: [MatchedQuery] -> ShowS # | |
Eq MatchedQuery Source # | |
Defined in Auth.Biscuit.Datalog.Executor (==) :: MatchedQuery -> MatchedQuery -> Bool # (/=) :: MatchedQuery -> MatchedQuery -> Bool # |
getBindings :: AuthorizationSuccess -> Set Bindings Source #
Get the matched variables from the allow
query used to authorize the biscuit.
This can be used in conjuction with getVariableValues
or getSingleVariableValue
to extract the actual values
class ToTerm t inSet pof where Source #
This class describes how to turn a haskell value into a datalog value. | This is used when slicing a haskell variable in a datalog expression
toTerm :: t -> Term' inSet pof 'Representation Source #
How to turn a value into a datalog item
Instances
ToTerm ByteString inSet pof Source # | |
Defined in Auth.Biscuit.Datalog.AST toTerm :: ByteString -> Term' inSet pof 'Representation Source # | |
ToTerm Text inSet pof Source # | |
Defined in Auth.Biscuit.Datalog.AST | |
ToTerm UTCTime inSet pof Source # | |
Defined in Auth.Biscuit.Datalog.AST toTerm :: UTCTime -> Term' inSet pof 'Representation Source # | |
ToTerm Integer inSet pof Source # | |
Defined in Auth.Biscuit.Datalog.AST | |
ToTerm Bool inSet pof Source # | |
Defined in Auth.Biscuit.Datalog.AST | |
ToTerm Int inSet pof Source # | |
Defined in Auth.Biscuit.Datalog.AST | |
(Foldable f, ToTerm a 'WithinSet 'InFact) => ToTerm (f a) 'NotWithinSet pof Source # | |
Defined in Auth.Biscuit.Datalog.AST toTerm :: f a -> Term' 'NotWithinSet pof 'Representation Source # |
class FromValue t where Source #
This class describes how to turn a datalog value into a regular haskell value.
type Term = Term' 'NotWithinSet 'InPredicate 'Representation Source #
In a regular AST, slices have already been eliminated
data Term' (inSet :: IsWithinSet) (pof :: PredicateOrFact) (ctx :: DatalogContext) Source #
A single datalog item. | This can be a value, a set of items, or a slice (a value that will be injected later), | depending on the context
Variable (VariableType inSet pof) | A variable (eg. |
LInteger Int | An integer literal (eg. |
LString Text | A string literal (eg. |
LDate UTCTime | A date literal (eg. |
LBytes ByteString | A hex literal (eg. |
LBool Bool | A bool literal (eg. |
Antiquote (SliceType ctx) | A slice (eg. |
TermSet (SetType inSet ctx) | A set (eg. |
Instances
FromValue Value Source # | |
(Lift (VariableType inSet pof), Lift (SetType inSet ctx), Lift (SliceType ctx)) => Lift (Term' inSet pof ctx :: Type) Source # | |
(Show (VariableType inSet pof), Show (SliceType ctx), Show (SetType inSet ctx)) => Show (Term' inSet pof ctx) Source # | |
(Eq (VariableType inSet pof), Eq (SliceType ctx), Eq (SetType inSet ctx)) => Eq (Term' inSet pof ctx) Source # | |
(Ord (VariableType inSet pof), Ord (SliceType ctx), Ord (SetType inSet ctx)) => Ord (Term' inSet pof ctx) Source # | |
Defined in Auth.Biscuit.Datalog.AST compare :: Term' inSet pof ctx -> Term' inSet pof ctx -> Ordering # (<) :: Term' inSet pof ctx -> Term' inSet pof ctx -> Bool # (<=) :: Term' inSet pof ctx -> Term' inSet pof ctx -> Bool # (>) :: Term' inSet pof ctx -> Term' inSet pof ctx -> Bool # (>=) :: Term' inSet pof ctx -> Term' inSet pof ctx -> Bool # max :: Term' inSet pof ctx -> Term' inSet pof ctx -> Term' inSet pof ctx # min :: Term' inSet pof ctx -> Term' inSet pof ctx -> Term' inSet pof ctx # |
Retrieving information from a biscuit
queryAuthorizerFacts :: AuthorizedBiscuit p -> Query -> Set Bindings Source #
Query the facts generated during authorization. This can be used in conjuction
with getVariableValues
and getSingleVariableValue
to retrieve actual values.
⚠ By default, only facts from the authority block and the authorizer are queried,
like what happens in rules and checks. Facts from other blocks can be queried
with a trusting
annotation. Be careful with trusting previous
, as it queries
facts from all blocks, even untrusted ones.
💁 If the facts you want to query are part of an allow query in the authorizer,
you can directly get values by calling getBindings
on AuthorizationSuccess
.
💁 If you are trying to extract facts from a biscuit in order to generate an
authorizer, have a look at queryRawBiscuitFacts
instead.
queryRawBiscuitFacts :: Biscuit openOrSealed check -> Query -> Set Bindings Source #
Query the facts generated by the authority and authorizer blocks
during authorization. This can be used in conjuction with getVariableValues
and getSingleVariableValue
to retrieve actual values.
⚠ By default, only facts from the authority block and the authorizer are queried,
like what happens in rules and checks. Facts from other blocks can be queried
with a trusting
annotation. Be careful with trusting previous
, as it queries
facts from all blocks, even untrusted ones.
💁 If the facts you want to query are part of an allow query in the authorizer,
you can directly get values by calling getBindings
on AuthorizationSuccess
.
getVariableValues :: (Ord t, FromValue t) => Set Bindings -> Text -> Set t Source #
Extract a set of values from a matched variable for a specific type.
Returning Set Value
allows to get all values, whatever their type.
getSingleVariableValue :: (Ord t, FromValue t) => Set Bindings -> Text -> Maybe t Source #
Extract exactly one value from a matched variable. If the variable has 0
matches or more than one match, Nothing
will be returned
query :: QuasiQuoter Source #
Compile-time parser for a query expression, intended to be used with the
QuasiQuotes
extension.
A typical use of query
looks like this:
[query|user($user_id) or group($group_id)|]
getRevocationIds :: Biscuit proof check -> NonEmpty ByteString Source #
Extract the list of revocation ids from a biscuit.
To reject revoked biscuits, please use parseWith
instead. This function
should only be used for inspecting biscuits, not for deciding whether to
reject them or not.