Create internal capability for json errors for connect (#809)
* Create internal capability for json errors for connect * Update error codes
This commit is contained in:
1 parent
f6e50006fc
commit
589c79831f
1 file changed
+71
-47
@@ -95,6 +95,7 @@ type Command struct {
|
||||
execCmdReturnValue *atomic.Int32
|
||||
proxyCtx context.Context
|
||||
proxyCancel context.CancelFunc
|
||||
outputJsonErrors bool
|
||||
}
|
||||
|
||||
func (c *Command) Synopsis() string {
|
||||
@@ -198,6 +199,15 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
Usage: "Target scope name, if authorizing the session via scope parameters and target name. Mutually exclusive with -scope-id.",
|
||||
})
|
||||
|
||||
f.BoolVar(&base.BoolVar{
|
||||
Name: "output-json-errors",
|
||||
Target: &c.outputJsonErrors,
|
||||
EnvVar: "BOUNDARY_CONNECT_OUTPUT_JSON_ERRORS",
|
||||
Completion: complete.PredictNothing,
|
||||
Usage: "Cause errors coming from this command to be output as JSON. This is experimental only and currently only meant for internal purposes. The format may change at any time and this flag/env var may be removed or modified at any time.",
|
||||
Hidden: true,
|
||||
})
|
||||
|
||||
switch c.Func {
|
||||
case "connect":
|
||||
f.StringVar(&base.StringVar{
|
||||
@@ -252,31 +262,31 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
f := c.Flags()
|
||||
|
||||
if err := f.Parse(args); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
c.Error(err.Error())
|
||||
return 3
|
||||
}
|
||||
|
||||
switch {
|
||||
case c.flagAuthzToken != "":
|
||||
switch {
|
||||
case c.flagTargetId != "":
|
||||
c.UI.Error(`-target-id and -authz-token cannot both be specified`)
|
||||
return 1
|
||||
c.Error(`-target-id and -authz-token cannot both be specified`)
|
||||
return 3
|
||||
case c.flagTargetName != "":
|
||||
c.UI.Error(`-target-name and -authz-token cannot both be specified`)
|
||||
return 1
|
||||
c.Error(`-target-name and -authz-token cannot both be specified`)
|
||||
return 3
|
||||
}
|
||||
default:
|
||||
if c.flagTargetId == "" &&
|
||||
(c.flagTargetName == "" ||
|
||||
(c.FlagScopeId == "" && c.FlagScopeName == "")) {
|
||||
c.UI.Error("Target ID was not passed in, but no combination of target name and scope ID/name was passed in either")
|
||||
return 1
|
||||
c.Error("Target ID was not passed in, but no combination of target name and scope ID/name was passed in either")
|
||||
return 3
|
||||
}
|
||||
if c.flagTargetId != "" &&
|
||||
(c.flagTargetName != "" || c.FlagScopeId != "" || c.FlagScopeName != "") {
|
||||
c.UI.Error("Cannot specify a target ID and also other lookup parameters")
|
||||
return 1
|
||||
c.Error("Cannot specify a target ID and also other lookup parameters")
|
||||
return 3
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,8 +305,8 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
|
||||
tofuToken, err := base62.Random(20)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Could not derive random bytes for tofu token: %w", err).Error())
|
||||
return 1
|
||||
c.Error(fmt.Errorf("Could not derive random bytes for tofu token: %w", err).Error())
|
||||
return 2
|
||||
}
|
||||
|
||||
c.connsLeftCh = make(chan int32)
|
||||
@@ -306,8 +316,8 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
}
|
||||
listenAddr := net.ParseIP(c.flagListenAddr)
|
||||
if listenAddr == nil {
|
||||
c.UI.Error(fmt.Sprintf("Could not successfully parse listen address of %s", c.flagListenAddr))
|
||||
return 1
|
||||
c.Error(fmt.Sprintf("Could not successfully parse listen address of %s", c.flagListenAddr))
|
||||
return 3
|
||||
}
|
||||
|
||||
authzString := c.flagAuthzToken
|
||||
@@ -316,19 +326,19 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
if authzString == "-" {
|
||||
authBytes, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("No authorization string was provided and encountered the following error attempting to read it from stdin: %w", err).Error())
|
||||
return 1
|
||||
c.Error(fmt.Errorf("No authorization string was provided and encountered the following error attempting to read it from stdin: %w", err).Error())
|
||||
return 3
|
||||
}
|
||||
if len(authBytes) == 0 {
|
||||
c.UI.Error("No authorization data read from stdin")
|
||||
return 1
|
||||
c.Error("No authorization data read from stdin")
|
||||
return 3
|
||||
}
|
||||
authzString = string(authBytes)
|
||||
}
|
||||
|
||||
if authzString == "" {
|
||||
c.UI.Error("Authorization data was empty")
|
||||
return 1
|
||||
c.Error("Authorization data was empty")
|
||||
return 3
|
||||
}
|
||||
|
||||
if authzString[0] == '{' {
|
||||
@@ -343,7 +353,7 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
default:
|
||||
client, err := c.Client()
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
|
||||
c.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
|
||||
return 2
|
||||
}
|
||||
targetClient := targets.NewClient(client)
|
||||
@@ -365,10 +375,15 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
sar, err := targetClient.AuthorizeSession(c.Context, c.flagTargetId, opts...)
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error from controller when performing authorize-session against target: %s", base.PrintApiError(apiErr)))
|
||||
switch c.outputJsonErrors {
|
||||
case true:
|
||||
c.Error(apiErr.ResponseBody().String())
|
||||
default:
|
||||
c.Error(fmt.Sprintf("Error from controller when performing authorize-session against target: %s", base.PrintApiError(apiErr)))
|
||||
}
|
||||
return 1
|
||||
}
|
||||
c.UI.Error(fmt.Sprintf("Error trying to authorize a session against target: %s", err.Error()))
|
||||
c.Error(fmt.Sprintf("Error trying to authorize a session against target: %s", err.Error()))
|
||||
return 2
|
||||
}
|
||||
authzString = sar.GetItem().(*targets.SessionAuthorization).AuthorizationToken
|
||||
@@ -376,23 +391,23 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
|
||||
marshaled, err := base58.FastBase58Decoding(authzString)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Unable to base58-decode authorization data: %w", err).Error())
|
||||
return 1
|
||||
c.Error(fmt.Errorf("Unable to base58-decode authorization data: %w", err).Error())
|
||||
return 3
|
||||
}
|
||||
if len(marshaled) == 0 {
|
||||
c.UI.Error("Zero length authorization information after decoding")
|
||||
return 1
|
||||
c.Error("Zero length authorization information after decoding")
|
||||
return 3
|
||||
}
|
||||
|
||||
c.sessionAuthzData = new(targetspb.SessionAuthorizationData)
|
||||
if err := proto.Unmarshal(marshaled, c.sessionAuthzData); err != nil {
|
||||
c.UI.Error(fmt.Errorf("Unable to proto-decode authorization data: %w", err).Error())
|
||||
return 1
|
||||
c.Error(fmt.Errorf("Unable to proto-decode authorization data: %w", err).Error())
|
||||
return 3
|
||||
}
|
||||
|
||||
if len(c.sessionAuthzData.GetWorkerInfo()) == 0 {
|
||||
c.UI.Error("No workers found in authorization string")
|
||||
return 1
|
||||
c.Error("No workers found in authorization string")
|
||||
return 3
|
||||
}
|
||||
|
||||
c.connectionsLeft.Store(c.sessionAuthzData.ConnectionLimit)
|
||||
@@ -400,13 +415,13 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
|
||||
parsedCert, err := x509.ParseCertificate(c.sessionAuthzData.Certificate)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Unable to decode mTLS certificate: %w", err).Error())
|
||||
return 1
|
||||
c.Error(fmt.Errorf("Unable to decode mTLS certificate: %w", err).Error())
|
||||
return 3
|
||||
}
|
||||
|
||||
if len(parsedCert.DNSNames) != 1 {
|
||||
c.UI.Error(fmt.Errorf("mTLS certificate has invalid parameters: %w", err).Error())
|
||||
return 1
|
||||
c.Error(fmt.Errorf("mTLS certificate has invalid parameters: %w", err).Error())
|
||||
return 3
|
||||
}
|
||||
|
||||
c.expiration = parsedCert.NotAfter
|
||||
@@ -445,16 +460,16 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
Port: c.flagListenPort,
|
||||
})
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error starting listening port: %w", err).Error())
|
||||
return 1
|
||||
c.Error(fmt.Errorf("Error starting listening port: %w", err).Error())
|
||||
return 2
|
||||
}
|
||||
|
||||
listenerCloseFunc := func() {
|
||||
// Forces the for loop to exist instead of spinning on errors
|
||||
c.connectionsLeft.Store(0)
|
||||
if err := c.listener.Close(); err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error closing listener on shutdown: %w", err).Error())
|
||||
retCode = 1
|
||||
c.Error(fmt.Errorf("Error closing listener on shutdown: %w", err).Error())
|
||||
retCode = 2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,8 +496,8 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
case "json":
|
||||
out, err := json.Marshal(&sessInfo)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("error marshaling session information: %w", err).Error())
|
||||
return 1
|
||||
c.Error(fmt.Errorf("error marshaling session information: %w", err).Error())
|
||||
return 2
|
||||
}
|
||||
c.UI.Output(string(out))
|
||||
}
|
||||
@@ -507,7 +522,7 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
if c.connectionsLeft.Load() == 0 {
|
||||
return
|
||||
}
|
||||
c.UI.Error(fmt.Errorf("Error accepting connection: %w", err).Error())
|
||||
c.Error(fmt.Errorf("Error accepting connection: %w", err).Error())
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -519,7 +534,7 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
workerAddr,
|
||||
tofuToken,
|
||||
transport); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
c.Error(err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -586,8 +601,8 @@ func (c *Command) Run(args []string) (retCode int) {
|
||||
case "json":
|
||||
out, err := json.Marshal(&termInfo)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("error marshaling termination information: %w", err).Error())
|
||||
return 1
|
||||
c.Error(fmt.Errorf("error marshaling termination information: %w", err).Error())
|
||||
return 2
|
||||
}
|
||||
c.UI.Output(string(out))
|
||||
}
|
||||
@@ -700,7 +715,7 @@ func (c *Command) updateConnsLeft(connsLeft int32) {
|
||||
case "json":
|
||||
out, err := json.Marshal(&connInfo)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("error marshaling connection information: %w", err).Error())
|
||||
c.Error(fmt.Errorf("error marshaling connection information: %w", err).Error())
|
||||
}
|
||||
c.UI.Output(string(out))
|
||||
}
|
||||
@@ -778,9 +793,18 @@ func (c *Command) handleExec(passthroughArgs []string) {
|
||||
}
|
||||
}
|
||||
|
||||
c.UI.Error(fmt.Sprintf("Failed to run command: %s", err))
|
||||
c.Error(fmt.Sprintf("Failed to run command: %s", err))
|
||||
c.execCmdReturnValue.Store(int32(exitCode))
|
||||
return
|
||||
}
|
||||
c.execCmdReturnValue.Store(0)
|
||||
}
|
||||
|
||||
func (c *Command) Error(err string) {
|
||||
switch c.outputJsonErrors {
|
||||
case true:
|
||||
c.UI.Error(fmt.Sprintf(`{"error": %q}`, err))
|
||||
default:
|
||||
c.UI.Error(err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user