You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
loop/lsat/caveat_test.go

203 lines
4.7 KiB
Go

package lsat
import (
"errors"
"testing"
"gopkg.in/macaroon.v2"
)
var (
testMacaroon, _ = macaroon.New(nil, nil, "", macaroon.LatestVersion)
)
// TestCaveatSerialization ensures that we can properly encode/decode valid
// caveats and cannot do so for invalid ones.
func TestCaveatSerialization(t *testing.T) {
t.Parallel()
tests := []struct {
name string
caveatStr string
err error
}{
{
name: "valid caveat",
caveatStr: "expiration=1337",
err: nil,
},
{
name: "valid caveat with separator in value",
caveatStr: "expiration=1337=",
err: nil,
},
{
name: "invalid caveat",
caveatStr: "expiration:1337",
err: ErrInvalidCaveat,
},
}
for _, test := range tests {
test := test
success := t.Run(test.name, func(t *testing.T) {
caveat, err := DecodeCaveat(test.caveatStr)
if !errors.Is(err, test.err) {
t.Fatalf("expected err \"%v\", got \"%v\"",
test.err, err)
}
if test.err != nil {
return
}
caveatStr := EncodeCaveat(caveat)
if caveatStr != test.caveatStr {
t.Fatalf("expected encoded caveat \"%v\", "+
"got \"%v\"", test.caveatStr, caveatStr)
}
})
if !success {
return
}
}
}
// TestHasCaveat ensures we can determine whether a macaroon contains a caveat
// with a specific condition.
func TestHasCaveat(t *testing.T) {
t.Parallel()
const (
cond = "cond"
value = "value"
)
m := testMacaroon.Clone()
// The macaroon doesn't have any caveats, so we shouldn't find any.
if _, ok := HasCaveat(m, cond); ok {
t.Fatal("found unexpected caveat with unknown condition")
}
// Add two caveats, one in a valid LSAT format and another invalid.
// We'll test that we're still able to determine the macaroon contains
// the valid caveat even though there is one that is invalid.
invalidCaveat := []byte("invalid")
if err := m.AddFirstPartyCaveat(invalidCaveat); err != nil {
t.Fatalf("unable to add macaroon caveat: %v", err)
}
validCaveat1 := Caveat{Condition: cond, Value: value}
if err := AddFirstPartyCaveats(m, validCaveat1); err != nil {
t.Fatalf("unable to add macaroon caveat: %v", err)
}
caveatValue, ok := HasCaveat(m, cond)
if !ok {
t.Fatal("expected macaroon to contain caveat")
}
if caveatValue != validCaveat1.Value {
t.Fatalf("expected caveat value \"%v\", got \"%v\"",
validCaveat1.Value, caveatValue)
}
// If we add another caveat with the same condition, the value of the
// most recently added caveat should be returned instead.
validCaveat2 := validCaveat1
validCaveat2.Value += value
if err := AddFirstPartyCaveats(m, validCaveat2); err != nil {
t.Fatalf("unable to add macaroon caveat: %v", err)
}
caveatValue, ok = HasCaveat(m, cond)
if !ok {
t.Fatal("expected macaroon to contain caveat")
}
if caveatValue != validCaveat2.Value {
t.Fatalf("expected caveat value \"%v\", got \"%v\"",
validCaveat2.Value, caveatValue)
}
}
// TestVerifyCaveats ensures caveat verification only holds true for known
// caveats.
func TestVerifyCaveats(t *testing.T) {
t.Parallel()
caveat1 := Caveat{Condition: "1", Value: "test"}
caveat2 := Caveat{Condition: "2", Value: "test"}
satisfier := Satisfier{
Condition: caveat1.Condition,
SatisfyPrevious: func(c Caveat, prev Caveat) error {
return nil
},
SatisfyFinal: func(c Caveat) error {
return nil
},
}
invalidSatisfyPrevious := func(c Caveat, prev Caveat) error {
return errors.New("no")
}
invalidSatisfyFinal := func(c Caveat) error {
return errors.New("no")
}
tests := []struct {
name string
caveats []Caveat
satisfiers []Satisfier
shouldFail bool
}{
{
name: "simple verification",
caveats: []Caveat{caveat1},
satisfiers: []Satisfier{satisfier},
shouldFail: false,
},
{
name: "unknown caveat",
caveats: []Caveat{caveat1, caveat2},
satisfiers: []Satisfier{satisfier},
shouldFail: false,
},
{
name: "one invalid",
caveats: []Caveat{caveat1, caveat2},
satisfiers: []Satisfier{
satisfier,
{
Condition: caveat2.Condition,
SatisfyFinal: invalidSatisfyFinal,
},
},
shouldFail: true,
},
{
name: "prev invalid",
caveats: []Caveat{caveat1, caveat1},
satisfiers: []Satisfier{
{
Condition: caveat1.Condition,
SatisfyPrevious: invalidSatisfyPrevious,
},
},
shouldFail: true,
},
}
for _, test := range tests {
test := test
success := t.Run(test.name, func(t *testing.T) {
err := VerifyCaveats(test.caveats, test.satisfiers...)
if test.shouldFail && err == nil {
t.Fatal("expected caveat verification to fail")
}
if !test.shouldFail && err != nil {
t.Fatal("unexpected caveat verification failure")
}
})
if !success {
return
}
}
}