| // 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) |
| } |
| } |