mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 04:28:08 +00:00 
			
		
		
		
	* dev docs: clarify internal and external token helpers * Add docs for DefaultTokenHelper
		
			
				
	
	
		
			134 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package token
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"os/exec"
 | 
						|
	"path/filepath"
 | 
						|
	"runtime"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
// ExternalTokenHelperPath should only be used in dev mode.
 | 
						|
// ExternalTokenHelperPath takes the configured path to a helper and expands it to
 | 
						|
// a full absolute path that can be executed. As of 0.5, the default token
 | 
						|
// helper is internal, to avoid problems running in dev mode (see GH-850 and
 | 
						|
// GH-783), so special assumptions of prepending "vault token-" no longer
 | 
						|
// apply.
 | 
						|
//
 | 
						|
// As an additional result, only absolute paths are now allowed. Looking in the
 | 
						|
// path or a current directory for an arbitrary executable could allow someone
 | 
						|
// to switch the expected binary for one further up the path (or in the current
 | 
						|
// directory), potentially opening up execution of an arbitrary binary.
 | 
						|
func ExternalTokenHelperPath(path string) (string, error) {
 | 
						|
	if !filepath.IsAbs(path) {
 | 
						|
		var err error
 | 
						|
		path, err = filepath.Abs(path)
 | 
						|
		if err != nil {
 | 
						|
			return "", err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if _, err := os.Stat(path); err != nil {
 | 
						|
		return "", fmt.Errorf("unknown error getting the external helper path")
 | 
						|
	}
 | 
						|
 | 
						|
	return path, nil
 | 
						|
}
 | 
						|
 | 
						|
var _ TokenHelper = (*ExternalTokenHelper)(nil)
 | 
						|
 | 
						|
// ExternalTokenHelper should only be used in a dev mode. For all other cases,
 | 
						|
// InternalTokenHelper should be used.
 | 
						|
// ExternalTokenHelper is the struct that has all the logic for storing and retrieving
 | 
						|
// tokens from the token helper. The API for the helpers is simple: the
 | 
						|
// BinaryPath is executed within a shell with environment Env. The last argument
 | 
						|
// appended will be the operation, which is:
 | 
						|
//
 | 
						|
//   * "get" - Read the value of the token and write it to stdout.
 | 
						|
//   * "store" - Store the value of the token which is on stdin. Output
 | 
						|
//       nothing.
 | 
						|
//   * "erase" - Erase the contents stored. Output nothing.
 | 
						|
//
 | 
						|
// Any errors can be written on stdout. If the helper exits with a non-zero
 | 
						|
// exit code then the stderr will be made part of the error value.
 | 
						|
type ExternalTokenHelper struct {
 | 
						|
	BinaryPath string
 | 
						|
	Env        []string
 | 
						|
}
 | 
						|
 | 
						|
// Erase deletes the contents from the helper.
 | 
						|
func (h *ExternalTokenHelper) Erase() error {
 | 
						|
	cmd, err := h.cmd("erase")
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if output, err := cmd.CombinedOutput(); err != nil {
 | 
						|
		return fmt.Errorf("%q: %w", string(output), err)
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Get gets the token value from the helper.
 | 
						|
func (h *ExternalTokenHelper) Get() (string, error) {
 | 
						|
	var buf, stderr bytes.Buffer
 | 
						|
	cmd, err := h.cmd("get")
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	cmd.Stdout = &buf
 | 
						|
	cmd.Stderr = &stderr
 | 
						|
	if err := cmd.Run(); err != nil {
 | 
						|
		return "", fmt.Errorf("%q: %w", stderr.String(), err)
 | 
						|
	}
 | 
						|
 | 
						|
	return buf.String(), nil
 | 
						|
}
 | 
						|
 | 
						|
// Store stores the token value into the helper.
 | 
						|
func (h *ExternalTokenHelper) Store(v string) error {
 | 
						|
	buf := bytes.NewBufferString(v)
 | 
						|
	cmd, err := h.cmd("store")
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	cmd.Stdin = buf
 | 
						|
	if output, err := cmd.CombinedOutput(); err != nil {
 | 
						|
		return fmt.Errorf("%q: %w", string(output), err)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *ExternalTokenHelper) Path() string {
 | 
						|
	return h.BinaryPath
 | 
						|
}
 | 
						|
 | 
						|
func (h *ExternalTokenHelper) cmd(op string) (*exec.Cmd, error) {
 | 
						|
	script := strings.ReplaceAll(h.BinaryPath, "\\", "\\\\") + " " + op
 | 
						|
	cmd, err := ExecScript(script)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	cmd.Env = h.Env
 | 
						|
	return cmd, nil
 | 
						|
}
 | 
						|
 | 
						|
// ExecScript returns a command to execute a script
 | 
						|
func ExecScript(script string) (*exec.Cmd, error) {
 | 
						|
	var shell, flag string
 | 
						|
	if runtime.GOOS == "windows" {
 | 
						|
		shell = "cmd"
 | 
						|
		flag = "/C"
 | 
						|
	} else {
 | 
						|
		shell = "/bin/sh"
 | 
						|
		flag = "-c"
 | 
						|
	}
 | 
						|
	if other := os.Getenv("SHELL"); other != "" {
 | 
						|
		shell = other
 | 
						|
	}
 | 
						|
	cmd := exec.Command(shell, flag, script)
 | 
						|
	return cmd, nil
 | 
						|
}
 |