Files
threshold/internal/cmd/commands/connect/credentials.go
T
Timothy Messier b69d1c2e2e fix(cli): Fallback parsing of un-typed credentials (#2989)
The `boundary connect` subcommands attempt to parse the credentials to
use for brokering. This allows the subcommands to insert the credentials
automatically into the process called by the subcommand, i.e. `ssh` or
`psql`. There is some fallback logic to try a best attempt at parsing
the credential in cases where a credential type has not be set on the
credential source.

The bug was introduced with the recent change to the vault credential
library subtype being renamed from `vault` to `vault-generic`. This
fallback logic would only run if the credential source type was "vault"
or "static", so if the vault credential library was created without
specifying a credential-type, the credential would not be parsed and
automatically passed to the sub-process.

This fix removes the additional check on the credential source's type,
instead it will attempt to parse the credential, relying just on the
structure of the credential.

This also fixes a similar bug in the table output of secrets when using
`boundary connect` without a subcommand. The parsing of the credentials
for display in the table was only running for `vault` or `static`.

Blame: db42eafd7a
2023-02-21 16:38:42 -05:00

124 lines
3.3 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package connect
import (
"errors"
"github.com/hashicorp/boundary/api/targets"
"github.com/hashicorp/boundary/internal/credential"
"github.com/mitchellh/mapstructure"
)
type usernamePassword struct {
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
raw *targets.SessionCredential
consumed bool
}
type sshPrivateKey struct {
Username string `mapstructure:"username"`
PrivateKey string `mapstructure:"private_key"`
Passphrase string `mapstructure:"private_key_passphrase"`
raw *targets.SessionCredential
consumed bool
}
type credentials struct {
usernamePassword []usernamePassword
sshPrivateKey []sshPrivateKey
unspecified []*targets.SessionCredential
}
func (c credentials) unconsumedSessionCredentials() []*targets.SessionCredential {
out := make([]*targets.SessionCredential, 0, len(c.sshPrivateKey)+len(c.usernamePassword)+len(c.unspecified))
// Unspecified credentials cannot be consumed
out = append(out, c.unspecified...)
for _, c := range c.sshPrivateKey {
if !c.consumed {
out = append(out, c.raw)
}
}
for _, c := range c.usernamePassword {
if !c.consumed {
out = append(out, c.raw)
}
}
return out
}
func parseCredentials(creds []*targets.SessionCredential) (credentials, error) {
if creds == nil {
return credentials{}, nil
}
var out credentials
for _, cred := range creds {
if cred.CredentialSource == nil {
return credentials{}, errors.New("missing credential source")
}
var upCred usernamePassword
var spkCred sshPrivateKey
switch credential.Type(cred.CredentialSource.CredentialType) {
case credential.UsernamePasswordType:
// Decode attributes from credential struct
if err := mapstructure.Decode(cred.Credential, &upCred); err != nil {
return credentials{}, err
}
if upCred.Username != "" && upCred.Password != "" {
upCred.raw = cred
out.usernamePassword = append(out.usernamePassword, upCred)
continue
}
case credential.SshPrivateKeyType:
// Decode attributes from credential struct
if err := mapstructure.Decode(cred.Credential, &spkCred); err != nil {
return credentials{}, err
}
if spkCred.Username != "" && spkCred.PrivateKey != "" {
spkCred.raw = cred
out.sshPrivateKey = append(out.sshPrivateKey, spkCred)
continue
}
}
// Credential type is unspecified, make a best effort attempt to parse
// a credential from the Decoded field if it exists
if cred.Secret != nil && cred.Secret.Decoded != nil {
// Attempt unmarshaling into username password creds
if err := mapstructure.Decode(cred.Secret.Decoded, &upCred); err != nil {
return credentials{}, err
}
if upCred.Username != "" && upCred.Password != "" {
upCred.raw = cred
out.usernamePassword = append(out.usernamePassword, upCred)
continue
}
// Attempt unmarshaling into ssh private key creds
if err := mapstructure.Decode(cred.Secret.Decoded, &spkCred); err != nil {
return credentials{}, err
}
if spkCred.Username != "" && spkCred.PrivateKey != "" {
spkCred.raw = cred
out.sshPrivateKey = append(out.sshPrivateKey, spkCred)
continue
}
}
// We could not parse the credential
out.unspecified = append(out.unspecified, cred)
}
return out, nil
}