github.com/grailbio/base@v0.0.11/cmdutil/access.go (about)

     1  // Copyright 2018 GRAIL, Inc. All rights reserved.
     2  // Use of this source code is governed by the Apache-2.0
     3  // license that can be found in the LICENSE file.
     4  
     5  package cmdutil
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"time"
    12  
    13  	v23 "v.io/v23"
    14  	"v.io/v23/context"
    15  	"v.io/x/lib/cmdline"
    16  )
    17  
    18  // WriteBlessings will write the current principal and blessings to the
    19  // supplied io.Writer.
    20  func WriteBlessings(ctx *context.T, out io.Writer) {
    21  	// Mimic the principal dump output.
    22  	principal := v23.GetPrincipal(ctx)
    23  	fmt.Fprintf(out, "Public key: %s\n", principal.PublicKey())
    24  	fmt.Fprintf(out, "---------------- BlessingStore ----------------")
    25  	fmt.Fprint(out, principal.BlessingStore().DebugString())
    26  	fmt.Fprintf(out, "---------------- BlessingRoots ----------------")
    27  	fmt.Fprint(out, principal.Roots().DebugString())
    28  }
    29  
    30  // CheckAccess checkes that the current process has credentials that
    31  // will be valid for at least another 30 minutes. It is intended to
    32  // allow for more useful and obvious error reporting.
    33  func CheckAccess(ctx *context.T) (time.Duration, error) {
    34  	if principal := v23.GetPrincipal(ctx); principal != nil {
    35  		// We have access to some credentials so we'll try to load them.
    36  		_, err := v23.WithPrincipal(ctx, principal)
    37  		if err != nil {
    38  			return 0, err
    39  		}
    40  		blessings, _ := principal.BlessingStore().Default()
    41  		now := time.Now()
    42  		left := blessings.Expiry().Sub(now)
    43  		if blessings.Expiry().After(now.Add(30 * time.Minute)) {
    44  			return left, nil
    45  		}
    46  		if blessings.Expiry().IsZero() {
    47  			return left, fmt.Errorf("credentials are not set, try setting the V23_CREDENTIALS using 'export V23_CREDENTIALS=%s'", os.ExpandEnv("${HOME}/.v23"))
    48  		}
    49  		return left, fmt.Errorf("credentials are set to expire in %v, use grail-access to refresh them", left)
    50  	}
    51  	return 0, fmt.Errorf("credentials directory doesn't exist, use the grail-access and/or grail-role commands to create one and to login")
    52  }
    53  
    54  type runner struct {
    55  	access bool
    56  	ctxfn  func() *context.T
    57  	run    func(*context.T, *cmdline.Env, []string) error
    58  }
    59  
    60  // Run implements cmdline.Runner.
    61  func (r runner) Run(env *cmdline.Env, args []string) error {
    62  	ctx := r.ctxfn()
    63  	if os.Getenv("GRAIL_CMDUTIL_NO_ACCESS_CHECK") != "1" && r.access {
    64  		if _, err := CheckAccess(ctx); err != nil {
    65  			return err
    66  		}
    67  	}
    68  	return r.run(ctx, env, args)
    69  }
    70  
    71  // V23RunnerFunc is like cmdutil.RunnerFunc, but allows for a context.T
    72  // parameter that is given the context as obtained from ctxfn.
    73  func V23RunnerFunc(ctxfn func() *context.T, run func(*context.T, *cmdline.Env, []string) error) cmdline.Runner {
    74  	return RunnerFunc(runner{false, ctxfn, run}.Run)
    75  }
    76  
    77  // RunnerFuncWithAccessCheck is like V23RunnerFunc, but also calls CheckAccess
    78  // to test for credential existence/expiry.
    79  func RunnerFuncWithAccessCheck(ctxfn func() *context.T, run func(*context.T, *cmdline.Env, []string) error) cmdline.Runner {
    80  	return RunnerFunc(runner{true, ctxfn, run}.Run)
    81  }