Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions authorizer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package biscuit

import (
"context"
"errors"
"fmt"
"strings"
Expand All @@ -23,8 +24,8 @@ type Authorizer interface {
AddRule(rule Rule)
AddCheck(check Check)
AddPolicy(policy Policy)
Authorize() error
Query(rule Rule) (FactSet, error)
Authorize(ctx context.Context) error
Query(ctx context.Context, rule Rule) (FactSet, error)
Biscuit() *Biscuit
Reset()
PrintWorld() string
Expand Down Expand Up @@ -111,7 +112,7 @@ func (v *authorizer) AddPolicy(policy Policy) {
v.policies = append(v.policies, policy)
}

func (v *authorizer) Authorize() error {
func (v *authorizer) Authorize(ctx context.Context) error {
// if we load facts from the verifier before
// the token's fact and rules, we might get inconsistent symbols
// token ements should first be converted to builder elements
Expand All @@ -133,7 +134,7 @@ func (v *authorizer) Authorize() error {
v.world.AddRule(r.convert(v.symbols))
}

if err := v.world.Run(v.symbols); err != nil {
if err := v.world.Run(ctx, v.symbols); err != nil {
return err
}
v.dirty = true
Expand Down Expand Up @@ -226,7 +227,7 @@ func (v *authorizer) Authorize() error {
block_world.AddRule(r.convert(v.symbols))
}

if err := block_world.Run(v.symbols); err != nil {
if err := block_world.Run(ctx, v.symbols); err != nil {
return err
}

Expand Down Expand Up @@ -277,8 +278,8 @@ func (v *authorizer) Authorize() error {
}
}

func (v *authorizer) Query(rule Rule) (FactSet, error) {
if err := v.world.Run(v.symbols); err != nil {
func (v *authorizer) Query(ctx context.Context, rule Rule) (FactSet, error) {
if err := v.world.Run(ctx, v.symbols); err != nil {
return nil, err
}
v.dirty = true
Expand Down
11 changes: 7 additions & 4 deletions authorizer_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package biscuit

import (
"context"
"crypto/ed25519"
"crypto/rand"
"testing"
Expand All @@ -9,6 +10,7 @@ import (
)

func TestVerifierDefaultPolicy(t *testing.T) {
ctx := context.Background()
rng := rand.Reader
publicRoot, privateRoot, _ := ed25519.GenerateKey(rng)

Expand All @@ -29,15 +31,16 @@ func TestVerifierDefaultPolicy(t *testing.T) {
require.NoError(t, err)

v.AddPolicy(DefaultDenyPolicy)
err = v.Authorize()
err = v.Authorize(ctx)
require.Equal(t, err, ErrPolicyDenied)

v.Reset()
v.AddPolicy(DefaultAllowPolicy)
require.NoError(t, v.Authorize())
require.NoError(t, v.Authorize(ctx))
}

func TestVerifierPolicies(t *testing.T) {
ctx := context.Background()
rng := rand.Reader
publicRoot, privateRoot, _ := ed25519.GenerateKey(rng)

Expand Down Expand Up @@ -83,7 +86,7 @@ func TestVerifierPolicies(t *testing.T) {
IDs: []Term{String("some_file.txt")},
}})

require.NoError(t, v.Authorize())
require.NoError(t, v.Authorize(ctx))

v, err = b.Authorizer(publicRoot)
require.NoError(t, err)
Expand All @@ -96,7 +99,7 @@ func TestVerifierPolicies(t *testing.T) {
Name: "resource",
IDs: []Term{String("some_file.txt")},
}})
require.Equal(t, v.Authorize(), ErrNoMatchingPolicy)
require.Equal(t, v.Authorize(ctx), ErrNoMatchingPolicy)
}

func TestVerifierSerializeLoad(t *testing.T) {
Expand Down
36 changes: 34 additions & 2 deletions biscuit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package biscuit

import (
"bytes"
"context"
"crypto/rand"
"encoding/binary"

Expand Down Expand Up @@ -294,6 +295,37 @@ func (b *Biscuit) Seal(rng io.Reader) (*Biscuit, error) {
}, nil
}

func (b *Biscuit) Lookup(factName string) []string {
symbols := b.symbols.Clone()
datalogFactName := symbols.Sym(factName)

if b.authority.facts == nil {
return nil
}

for _, f := range *b.authority.facts {
if f.Name != datalogFactName {
continue
}

terms := make([]string, len(f.Terms))
for i, term := range f.Terms {
switch t := term.(type) {
case datalog.String:
terms[i] = symbols.Str(t)
case datalog.Variable:
terms[i] = symbols.Var(t)
default:
terms[i] = t.String()
}
}

return terms
}

return nil
}

type (
// A PublickKeyByIDProjection inspects an optional ID for a public key and returns the
// corresponding public key, if any. If it doesn't recognize the ID or can't find the public
Expand Down Expand Up @@ -568,7 +600,7 @@ func (b *Biscuit) checkRootKey(root ed25519.PublicKey) error {
return nil
}*/

func (b *Biscuit) generateWorld(symbols *datalog.SymbolTable) (*datalog.World, error) {
func (b *Biscuit) generateWorld(ctx context.Context, symbols *datalog.SymbolTable) (*datalog.World, error) {
world := datalog.NewWorld()

for _, fact := range *b.authority.facts {
Expand All @@ -589,7 +621,7 @@ func (b *Biscuit) generateWorld(symbols *datalog.SymbolTable) (*datalog.World, e
}
}

if err := world.Run(symbols); err != nil {
if err := world.Run(ctx, symbols); err != nil {
return nil, err
}

Expand Down
27 changes: 16 additions & 11 deletions biscuit_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package biscuit

import (
"context"
"crypto/ed25519"
"crypto/rand"
"fmt"
Expand All @@ -11,6 +12,7 @@ import (
)

func TestBiscuit(t *testing.T) {
ctx := context.Background()
rng := rand.Reader
const rootKeyID = 123
const contextText = "current_context"
Expand Down Expand Up @@ -106,21 +108,21 @@ func TestBiscuit(t *testing.T) {
v3.AddFact(Fact{Predicate: Predicate{Name: "resource", IDs: []Term{String("/a/file1")}}})
v3.AddFact(Fact{Predicate: Predicate{Name: "operation", IDs: []Term{String("read")}}})
v3.AddPolicy(DefaultAllowPolicy)
require.NoError(t, v3.Authorize())
require.NoError(t, v3.Authorize(ctx))

v3, err = b3deser.AuthorizerFor(WithSingularRootPublicKey(publicRoot))
require.NoError(t, err)
v3.AddFact(Fact{Predicate: Predicate{Name: "resource", IDs: []Term{String("/a/file2")}}})
v3.AddFact(Fact{Predicate: Predicate{Name: "operation", IDs: []Term{String("read")}}})
v3.AddPolicy(DefaultAllowPolicy)
require.Error(t, v3.Authorize())
require.Error(t, v3.Authorize(ctx))

v3, err = b3deser.AuthorizerFor(WithSingularRootPublicKey(publicRoot))
require.NoError(t, err)
v3.AddFact(Fact{Predicate: Predicate{Name: "resource", IDs: []Term{String("/a/file1")}}})
v3.AddFact(Fact{Predicate: Predicate{Name: "operation", IDs: []Term{String("write")}}})
v3.AddPolicy(DefaultAllowPolicy)
require.Error(t, v3.Authorize())
require.Error(t, v3.Authorize(ctx))
}

func TestSealedBiscuit(t *testing.T) {
Expand Down Expand Up @@ -181,6 +183,7 @@ func TestSealedBiscuit(t *testing.T) {
}

func TestBiscuitRules(t *testing.T) {
ctx := context.Background()
rng := rand.Reader
publicRoot, privateRoot, _ := ed25519.GenerateKey(rng)

Expand Down Expand Up @@ -222,7 +225,7 @@ func TestBiscuitRules(t *testing.T) {
// b1 should allow alice & bob only
// v, err := b1.Verify(publicRoot)
// require.NoError(t, err)
verifyOwner(t, *b1, publicRoot, map[string]bool{"alice": true, "bob": true, "eve": false})
verifyOwner(ctx, t, *b1, publicRoot, map[string]bool{"alice": true, "bob": true, "eve": false})

block := b1.CreateBlock()
block.AddCheck(Check{
Expand Down Expand Up @@ -255,10 +258,10 @@ func TestBiscuitRules(t *testing.T) {
// b2 should now only allow alice
// v, err = b2.Verify(publicRoot)
// require.NoError(t, err)
verifyOwner(t, *b2, publicRoot, map[string]bool{"alice": true, "bob": false, "eve": false})
verifyOwner(ctx, t, *b2, publicRoot, map[string]bool{"alice": true, "bob": false, "eve": false})
}

func verifyOwner(t *testing.T, b Biscuit, publicRoot ed25519.PublicKey, owners map[string]bool) {
func verifyOwner(ctx context.Context, t *testing.T, b Biscuit, publicRoot ed25519.PublicKey, owners map[string]bool) {
for user, valid := range owners {
v, err := b.AuthorizerFor(WithSingularRootPublicKey(publicRoot))
require.NoError(t, err)
Expand All @@ -278,9 +281,9 @@ func verifyOwner(t *testing.T, b Biscuit, publicRoot ed25519.PublicKey, owners m
v.AddPolicy(DefaultAllowPolicy)

if valid {
require.NoError(t, v.Authorize())
require.NoError(t, v.Authorize(ctx))
} else {
require.Error(t, v.Authorize())
require.Error(t, v.Authorize(ctx))
}
})
}
Expand Down Expand Up @@ -317,6 +320,7 @@ func TestCheckRootKey(t *testing.T) {
}

func TestGenerateWorld(t *testing.T) {
ctx := context.Background()
rng := rand.Reader
_, privateRoot, _ := ed25519.GenerateKey(rng)

Expand Down Expand Up @@ -349,7 +353,7 @@ func TestGenerateWorld(t *testing.T) {
require.NoError(t, err)

StringTable := (build.(*builderOptions)).symbols
world, err := b.generateWorld(defaultSymbolTable.Clone())
world, err := b.generateWorld(ctx, defaultSymbolTable.Clone())
require.NoError(t, err)

expectedWorld := datalog.NewWorld()
Expand All @@ -376,7 +380,7 @@ func TestGenerateWorld(t *testing.T) {
require.NoError(t, err)

allStrings := append(*StringTable, *(blockBuild.(*blockBuilder)).symbols...)
world, err = b2.generateWorld(&allStrings)
world, err = b2.generateWorld(ctx, &allStrings)
require.NoError(t, err)

expectedWorld = datalog.NewWorld()
Expand Down Expand Up @@ -575,6 +579,7 @@ func TestGetBlockID(t *testing.T) {
}

func TestInvalidRuleGeneration(t *testing.T) {
ctx := context.Background()
rng := rand.Reader
publicRoot, privateRoot, _ := ed25519.GenerateKey(rng)
builder := NewBuilder(privateRoot)
Expand Down Expand Up @@ -612,7 +617,7 @@ func TestInvalidRuleGeneration(t *testing.T) {
IDs: []Term{String("write")},
}})

err = verifier.Authorize()
err = verifier.Authorize(ctx)
t.Log(verifier.PrintWorld())
require.Error(t, err)
}
4 changes: 2 additions & 2 deletions datalog/datalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,9 +357,9 @@ func (w *World) Rules() []Rule {
return w.rules
}

func (w *World) Run(syms *SymbolTable) error {
func (w *World) Run(ctx context.Context, syms *SymbolTable) error {
done := make(chan error)
ctx, cancel := context.WithTimeout(context.Background(), w.runLimits.maxDuration)
ctx, cancel := context.WithTimeout(ctx, w.runLimits.maxDuration)
defer cancel()

go func() {
Expand Down
10 changes: 7 additions & 3 deletions datalog/datalog_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package datalog

import (
"context"
"crypto/rand"
"crypto/sha256"
"testing"
Expand All @@ -19,6 +20,8 @@ func hashVar(s string) Variable {
}

func TestFamily(t *testing.T) {
ctx := context.Background()

w := NewWorld()
syms := &SymbolTable{}
dbg := SymbolDebugger{syms}
Expand Down Expand Up @@ -57,12 +60,12 @@ func TestFamily(t *testing.T) {

t.Logf("adding r2: %s", dbg.Rule(r2))
w.AddRule(r2)
if err := w.Run(syms); err != nil {
if err := w.Run(ctx, syms); err != nil {
t.Error(err)
}

w.AddFact(Fact{Predicate{parent, []Term{c, e}}})
if err := w.Run(syms); err != nil {
if err := w.Run(ctx, syms); err != nil {
t.Error(err)
}

Expand Down Expand Up @@ -480,6 +483,7 @@ func TestSetEqual(t *testing.T) {
}

func TestWorldRunLimits(t *testing.T) {
ctx := context.Background()
syms := &SymbolTable{}
a := syms.Insert("A")
b := syms.Insert("B")
Expand Down Expand Up @@ -550,6 +554,6 @@ func TestWorldRunLimits(t *testing.T) {
}

w.AddRule(r1)
require.Equal(t, tc.expectedErr, w.Run(syms))
require.Equal(t, tc.expectedErr, w.Run(ctx, syms))
}
}
6 changes: 4 additions & 2 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package biscuit_test

import (
"context"
"crypto/ed25519"
"crypto/rand"
"fmt"
Expand All @@ -10,6 +11,7 @@ import (
)

func ExampleBiscuit() {
ctx := context.Background()
rng := rand.Reader
publicRoot, privateRoot, _ := ed25519.GenerateKey(rng)

Expand Down Expand Up @@ -88,7 +90,7 @@ func ExampleBiscuit() {
}
v1.AddAuthorizer(authorizer)

if err := v1.Authorize(); err != nil {
if err := v1.Authorize(ctx); err != nil {
// fmt.Println(v1.PrintWorld())

fmt.Println("forbidden to read /a/file1.txt")
Expand All @@ -111,7 +113,7 @@ func ExampleBiscuit() {
}
v1.AddAuthorizer(authorizer)

if err := v1.Authorize(); err != nil {
if err := v1.Authorize(ctx); err != nil {
fmt.Println("forbidden to write /a/file1.txt")
} else {
fmt.Println("allowed to write /a/file1.txt")
Expand Down
Loading
Loading