Skip to content

Commit

Permalink
Update format of secret to return both raw and decoded when possible (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jefferai authored Jun 30, 2021
1 parent 77bafca commit 7c3d5be
Show file tree
Hide file tree
Showing 15 changed files with 409 additions and 327 deletions.
4 changes: 1 addition & 3 deletions api/targets/session_credential.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions api/targets/session_secret.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions internal/api/genapi/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -560,15 +560,19 @@ var inputStructs = []*structInfo{
outFile: "targets/credential_library.gen.go",
},
{
inProto: &targets.SessionCredential{},
outFile: "targets/session_credential.gen.go",
inProto: &targets.SessionSecret{},
outFile: "targets/session_secret.gen.go",
fieldOverrides: []fieldInfo{
{
Name: "Secret",
Name: "Raw",
FieldType: "json.RawMessage",
},
},
},
{
inProto: &targets.SessionCredential{},
outFile: "targets/session_credential.gen.go",
},
{
inProto: &targets.SessionAuthorization{},
outFile: "targets/session_authorization.gen.go",
Expand Down
11 changes: 4 additions & 7 deletions internal/cmd/base/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/scopes"
"github.com/hashicorp/boundary/api/targets"
"github.com/mitchellh/cli"
"github.com/mitchellh/go-wordwrap"
"github.com/pkg/errors"
Expand Down Expand Up @@ -258,13 +257,11 @@ func (c *Command) PrintJsonItem(result api.GenericResult, opt ...Option) bool {
func (c *Command) PrintJson(input json.RawMessage, opt ...Option) bool {
opts := getOpts(opt...)
output := struct {
StatusCode int `json:"status_code,omitempty"`
DecodedCredentials []*targets.SessionCredential `json:"decoded_credentials,omitempty"`
Item json.RawMessage `json:"item,omitempty"`
StatusCode int `json:"status_code,omitempty"`
Item json.RawMessage `json:"item,omitempty"`
}{
StatusCode: opts.withStatusCode,
DecodedCredentials: opts.withDecodedCredentials,
Item: input,
StatusCode: opts.withStatusCode,
Item: input,
}
b, err := JsonFormatter{}.Format(output)
if err != nil {
Expand Down
10 changes: 0 additions & 10 deletions internal/cmd/base/option.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package base

import "github.com/hashicorp/boundary/api/targets"

// getOpts - iterate the inbound Options and return a struct.
func getOpts(opt ...Option) Options {
opts := getDefaultOptions()
Expand All @@ -28,7 +26,6 @@ type Options struct {
withDialect string
withAttributeFieldPrefix string
withStatusCode int
withDecodedCredentials []*targets.SessionCredential
}

func getDefaultOptions() Options {
Expand Down Expand Up @@ -131,10 +128,3 @@ func WithStatusCode(statusCode int) Option {
o.withStatusCode = statusCode
}
}

// WithDecodedCredentials allows passing decoded credentials
func WithDecodedCredentials(creds []*targets.SessionCredential) Option {
return func(o *Options) {
o.withDecodedCredentials = creds
}
}
29 changes: 0 additions & 29 deletions internal/cmd/commands/connect/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"crypto/ed25519"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -397,34 +396,6 @@ func (c *Command) Run(args []string) (retCode int) {
authzString = c.sessionAuthz.AuthorizationToken
}

if c.sessionAuthz != nil {
for _, cred := range c.sessionAuthz.Credentials {
// Since connect commands are helpers and are not meant as a direct CLI
// representation of the REST API, we can modify the credentials to be
// useful as a helper instead of trying to keep it as a faithful
// representation of what the api returns.
if len(cred.Secret) == 0 {
continue
}
switch cred.CredentialLibrary.Type {
case "vault":
// If it's Vault, the result will be JSON, except in specific
// circumstances that aren't used for credential fetching. So we
// can take the bytes as-is (after base64-decoding), but we'll
// format it nicely.
in, err := base64.StdEncoding.DecodeString(strings.Trim(string(cred.Secret), `"`))
if err != nil {
c.PrintCliError(fmt.Errorf("Error decoding secret as base64: %w", err))
return base.CommandCliError
}
// Now that it's decoded, pop it back in the same place as marshaled JSON
cred.Secret = in
default:
// If it's not Vault, and not another known type, leave it alone.
}
}
}

marshaled, err := base58.FastBase58Decoding(authzString)
if err != nil {
c.PrintCliError(fmt.Errorf("Unable to base58-decode authorization data: %w", err))
Expand Down
9 changes: 7 additions & 2 deletions internal/cmd/commands/connect/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package connect

import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"strings"
Expand Down Expand Up @@ -72,11 +73,15 @@ func generateCredentialTableOutputSlice(prefixIndent int, creds []*targets.Sessi

func fmtSecretForTable(indent int, sc *targets.SessionCredential) []string {
prefixStr := strings.Repeat(" ", indent)
origSecret := []string{fmt.Sprintf("%s %s", prefixStr, sc.Secret)}
origSecret := []string{fmt.Sprintf("%s %s", prefixStr, sc.Secret.Raw)}
switch sc.CredentialLibrary.Type {
case "vault":
in, err := base64.StdEncoding.DecodeString(strings.Trim(string(sc.Secret.Raw), `"`))
if err != nil {
return origSecret
}
dst := new(bytes.Buffer)
if err := json.Indent(dst, sc.Secret, fmt.Sprintf("%s ", prefixStr), fmt.Sprintf("%s ", prefixStr)); err != nil {
if err := json.Indent(dst, in, fmt.Sprintf("%s ", prefixStr), fmt.Sprintf("%s ", prefixStr)); err != nil {
return origSecret
}
secretStr := strings.Split(dst.String(), "\n")
Expand Down
13 changes: 8 additions & 5 deletions internal/cmd/commands/connect/postgres.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package connect

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"strings"

"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/mitchellh/mapstructure"
"github.com/posener/complete"
)

Expand Down Expand Up @@ -53,20 +53,23 @@ func (p *postgresFlags) defaultExec() string {
}

type postgresCredentials struct {
Username string `json:"username"`
Password string `json:"password"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
}

func (p *postgresFlags) buildArgs(c *Command, port, ip, addr string) (args, envs []string, retErr error) {
var creds postgresCredentials
if c.sessionAuthz != nil && len(c.sessionAuthz.Credentials) > 0 {
for _, cred := range c.sessionAuthz.Credentials {
if cred.Secret == nil || cred.Secret.Decoded == nil {
continue
}
// TODO: Could allow switching on library ID or name
switch cred.CredentialLibrary.Type {
case "vault":
// Attempt unmarshaling into creds
if err := json.Unmarshal(cred.Secret, &creds); err != nil {
return nil, nil, fmt.Errorf("Error unmarshaling Vault secret: %w", err)
if err := mapstructure.Decode(cred.Secret.Decoded, &creds); err != nil {
return nil, nil, fmt.Errorf("Error interpreting Vault secret: %w", err)
}
}

Expand Down
32 changes: 3 additions & 29 deletions internal/cmd/commands/targetscmd/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ func printCustomActionOutputImpl(c *Command) (bool, error) {
)

for _, cred := range item.Credentials {
if len(cred.Secret) == 0 {
if cred.Secret == nil || len(cred.Secret.Raw) == 0 {
continue
}

Expand All @@ -629,7 +629,7 @@ func printCustomActionOutputImpl(c *Command) (bool, error) {
// credential fetching. So we can take the bytes
// as-is (after base64-decoding), but we'll format
// it nicely.
in, err := base64.StdEncoding.DecodeString(strings.Trim(string(cred.Secret), `"`))
in, err := base64.StdEncoding.DecodeString(strings.Trim(string(cred.Secret.Raw), `"`))
if err != nil {
return false, fmt.Errorf("Error decoding secret as base64: %w", err)
}
Expand Down Expand Up @@ -658,33 +658,7 @@ func printCustomActionOutputImpl(c *Command) (bool, error) {
return true, nil

case "json":
if len(item.Credentials) > 0 {
for _, cred := range item.Credentials {
if len(cred.Secret) == 0 {
continue
}

switch cred.CredentialLibrary.Type {
case "vault":
// If it's Vault, the result will be JSON, except in
// specific circumstances that aren't used for
// credential fetching. So we can take the bytes
// as-is (after base64-decoding), but we'll format
// it nicely.
in, err := base64.StdEncoding.DecodeString(strings.Trim(string(cred.Secret), `"`))
if err != nil {
return false, fmt.Errorf("Error decoding secret as base64: %w", err)
}
// Now that it's decoded, pop it back in the same place
// as marshaled JSON
cred.Secret = in
default:
// If it's not Vault, and not another known type,
// leave it alone.
}
}
}
if ok := c.PrintJsonItem(c.sar, base.WithDecodedCredentials(item.Credentials)); !ok {
if ok := c.PrintJsonItem(c.sar); !ok {
return false, fmt.Errorf("Error formatting as JSON")
}
return true, nil
Expand Down
18 changes: 17 additions & 1 deletion internal/gen/controller.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -4266,13 +4266,29 @@
"readOnly": true
},
"secret": {
"type": "string",
"$ref": "#/definitions/controller.api.resources.targets.v1.SessionSecret",
"description": "Output only. The secret of this credential base64 encoded.",
"readOnly": true
}
},
"description": "A credential for a session."
},
"controller.api.resources.targets.v1.SessionSecret": {
"type": "object",
"properties": {
"raw": {
"type": "string",
"description": "Output only. The base64-encoded value representing the raw bytes from the\ncredential provider.",
"readOnly": true
},
"decoded": {
"type": "object",
"description": "Output only. The decoded raw string, if a JSON object.",
"readOnly": true
}
},
"description": "The actual secret for a session credential."
},
"controller.api.resources.targets.v1.Target": {
"type": "object",
"properties": {
Expand Down
Loading

0 comments on commit 7c3d5be

Please sign in to comment.