ref/lib/security: Add a method to PrepareDischarges.
Change-Id: I4475b039c2252526e00f0ba406254d0950822da6
diff --git a/lib/security/prepare_discharges_test.go b/lib/security/prepare_discharges_test.go
new file mode 100644
index 0000000..292c58e
--- /dev/null
+++ b/lib/security/prepare_discharges_test.go
@@ -0,0 +1,137 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package security_test
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ "v.io/v23"
+ "v.io/v23/context"
+ "v.io/v23/rpc"
+ "v.io/v23/security"
+ securitylib "v.io/x/ref/lib/security"
+ "v.io/x/ref/lib/xrpc"
+ _ "v.io/x/ref/runtime/factories/generic"
+ "v.io/x/ref/test"
+ "v.io/x/ref/test/testutil"
+)
+
+func init() {
+ test.Init()
+}
+
+type expiryDischarger struct {
+ called bool
+}
+
+func (ed *expiryDischarger) Discharge(ctx *context.T, call rpc.StreamServerCall, cav security.Caveat, _ security.DischargeImpetus) (security.Discharge, error) {
+ tp := cav.ThirdPartyDetails()
+ if tp == nil {
+ return security.Discharge{}, fmt.Errorf("discharger: %v does not represent a third-party caveat", cav)
+ }
+ if err := tp.Dischargeable(ctx, call.Security()); err != nil {
+ return security.Discharge{}, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", cav, err)
+ }
+ expDur := 10 * time.Millisecond
+ if ed.called {
+ expDur = time.Second
+ }
+ expiry, err := security.NewExpiryCaveat(time.Now().Add(expDur))
+ if err != nil {
+ return security.Discharge{}, fmt.Errorf("failed to create an expiration on the discharge: %v", err)
+ }
+ d, err := call.Security().LocalPrincipal().MintDischarge(cav, expiry)
+ if err != nil {
+ return security.Discharge{}, err
+ }
+ ctx.Infof("got discharge on sever %#v", d)
+ ed.called = true
+ return d, nil
+}
+
+func TestPrepareDischarges(t *testing.T) {
+ ctx, shutdown := test.V23Init()
+ defer shutdown()
+
+ pclient := testutil.NewPrincipal("client")
+ cctx, err := v23.WithPrincipal(ctx, pclient)
+ if err != nil {
+ t.Fatal(err)
+ }
+ pdischarger := testutil.NewPrincipal("discharger")
+ dctx, err := v23.WithPrincipal(ctx, pdischarger)
+ if err != nil {
+ t.Fatal(err)
+ }
+ pclient.AddToRoots(pdischarger.BlessingStore().Default())
+ pclient.AddToRoots(v23.GetPrincipal(ctx).BlessingStore().Default())
+ pdischarger.AddToRoots(pclient.BlessingStore().Default())
+ pdischarger.AddToRoots(v23.GetPrincipal(ctx).BlessingStore().Default())
+
+ expcav, err := security.NewExpiryCaveat(time.Now().Add(time.Hour))
+ if err != nil {
+ t.Fatal(err)
+ }
+ tpcav, err := security.NewPublicKeyCaveat(
+ pdischarger.PublicKey(),
+ "discharger",
+ security.ThirdPartyRequirements{},
+ expcav)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cbless, err := pclient.BlessSelf("clientcaveats", tpcav)
+ if err != nil {
+ t.Fatal(err)
+ }
+ tpid := tpcav.ThirdPartyDetails().ID()
+
+ v23.GetPrincipal(dctx)
+ _, err = xrpc.NewServer(dctx,
+ "discharger",
+ &expiryDischarger{},
+ security.AllowEveryone())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Fetch discharges for tpcav.
+ buffer := 100 * time.Millisecond
+ discharges := securitylib.PrepareDischarges(cctx, cbless,
+ security.DischargeImpetus{}, buffer)
+ if len(discharges) != 1 {
+ t.Errorf("Got %d discharges, expected 1.", len(discharges))
+ }
+ dis, has := discharges[tpid]
+ if !has {
+ t.Errorf("Got %#v, Expected discharge for %s", discharges, tpid)
+ }
+ // Check that the discharges is not yet expired, but is expired after 100 milliseconds.
+ expiry := dis.Expiry()
+ // The discharge should expire.
+ select {
+ case <-time.After(time.Now().Sub(expiry)):
+ break
+ case <-time.After(time.Second):
+ t.Fatalf("discharge didn't expire within a second")
+ }
+
+ // Preparing Discharges again to get fresh discharges.
+ discharges = securitylib.PrepareDischarges(cctx, cbless,
+ security.DischargeImpetus{}, buffer)
+ if len(discharges) != 1 {
+ t.Errorf("Got %d discharges, expected 1.", len(discharges))
+ }
+ dis, has = discharges[tpid]
+ if !has {
+ t.Errorf("Got %#v, Expected discharge for %s", discharges, tpid)
+ }
+ now := time.Now()
+ if expiry = dis.Expiry(); expiry.Before(now) {
+ t.Fatalf("discharge has expired %v, but should be fresh", dis)
+ }
+}