Merge pull request #6207 from hashicorp/llb-password-credential-type

Password credential type
This commit is contained in:
Justin Nguyen authored and GitHub committed 2025-11-14 12:00:23 -06:00
commit dc7f0b00fc
66 files changed
+5784 -947

No files matched your search

+12
View File
@@ -179,6 +179,18 @@ func WithJsonCredentialObject(inObject map[string]interface{}) Option {
}
}
func WithPasswordCredentialPassword(inPassword string) Option {
return func(o *options) {
raw, ok := o.postMap["attributes"]
if !ok {
raw = any(map[string]any{})
}
val := raw.(map[string]any)
val["password"] = inPassword
o.postMap["attributes"] = val
}
}
func WithUsernamePasswordCredentialPassword(inPassword string) Option {
return func(o *options) {
raw, ok := o.postMap["attributes"]
@@ -0,0 +1,41 @@
// Code generated by "make api"; DO NOT EDIT.
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package credentials
import (
"fmt"
"github.com/mitchellh/mapstructure"
)
type PasswordAttributes struct {
Password string `json:"password,omitempty"`
PasswordHmac string `json:"password_hmac,omitempty"`
}
func AttributesMapToPasswordAttributes(in map[string]any) (*PasswordAttributes, error) {
if in == nil {
return nil, fmt.Errorf("nil input map")
}
var out PasswordAttributes
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
Result: &out,
TagName: "json",
})
if err != nil {
return nil, fmt.Errorf("error creating mapstructure decoder: %w", err)
}
if err := dec.Decode(in); err != nil {
return nil, fmt.Errorf("error decoding: %w", err)
}
return &out, nil
}
func (pt *Credential) GetPasswordAttributes() (*PasswordAttributes, error) {
if pt.Type != "password" {
return nil, fmt.Errorf("asked to fetch %s-type attributes but credential is of type %s", "password", pt.Type)
}
return AttributesMapToPasswordAttributes(pt.Attributes)
}
+40
View File
@@ -12,6 +12,7 @@ import (
const (
usernamePasswordCredentialType = "username_password"
passwordCredentialType = "password"
sshPrivateKeyCredentialType = "ssh_private_key"
)
@@ -26,6 +27,16 @@ type UsernamePassword struct {
Consumed bool
}
// Password contains a password credential
type Password struct {
Password string `mapstructure:"password"`
Raw *targets.SessionCredential
// Consumed can be set by the caller to indicate that the credential has
// been used, e.g. displayed to the user
Consumed bool
}
// SshPrivateKey contains the username and private key with optional passphrase
// for the key
type SshPrivateKey struct {
@@ -41,6 +52,7 @@ type SshPrivateKey struct {
type Credentials struct {
UsernamePassword []UsernamePassword
Password []Password
SshPrivateKey []SshPrivateKey
// Unspecified are credentials that do not match one of the types above
Unspecified []*targets.SessionCredential
@@ -62,6 +74,11 @@ func (c Credentials) UnconsumedSessionCredentials() []*targets.SessionCredential
out = append(out, c.Raw)
}
}
for _, c := range c.Password {
if !c.Consumed {
out = append(out, c.Raw)
}
}
return out
}
@@ -76,6 +93,7 @@ func ParseCredentials(creds []*targets.SessionCredential) (Credentials, error) {
}
var upCred UsernamePassword
var pCred Password
var spkCred SshPrivateKey
switch cred.CredentialSource.CredentialType {
case usernamePasswordCredentialType:
@@ -90,6 +108,18 @@ func ParseCredentials(creds []*targets.SessionCredential) (Credentials, error) {
continue
}
case passwordCredentialType:
// Decode attributes from credential struct
if err := mapstructure.Decode(cred.Credential, &pCred); err != nil {
return Credentials{}, err
}
if pCred.Password != "" {
pCred.Raw = cred
out.Password = append(out.Password, pCred)
continue
}
case sshPrivateKeyCredentialType:
// Decode attributes from credential struct
if err := mapstructure.Decode(cred.Credential, &spkCred); err != nil {
@@ -116,6 +146,16 @@ func ParseCredentials(creds []*targets.SessionCredential) (Credentials, error) {
continue
}
// Attempt unmarshaling into password creds
if err := mapstructure.Decode(cred.Secret.Decoded, &pCred); err != nil {
return Credentials{}, err
}
if pCred.Password != "" {
pCred.Raw = cred
out.Password = append(out.Password, pCred)
continue
}
// Attempt unmarshaling into ssh private key creds
if err := mapstructure.Decode(cred.Secret.Decoded, &spkCred); err != nil {
return Credentials{}, err
+154 -1
View File
@@ -29,6 +29,15 @@ var (
},
}
typedPassword = &targets.SessionCredential{
CredentialSource: &targets.CredentialSource{
CredentialType: passwordCredentialType,
},
Credential: map[string]any{
"password": "pass",
},
}
typedSshPrivateKey = &targets.SessionCredential{
CredentialSource: &targets.CredentialSource{
CredentialType: sshPrivateKeyCredentialType,
@@ -75,6 +84,17 @@ var (
},
}
vaultPassword = &targets.SessionCredential{
CredentialSource: &targets.CredentialSource{
Type: vaultGenericLibrarySubtype,
},
Secret: &targets.SessionSecret{
Decoded: map[string]any{
"password": "vault-decoded-pass",
},
},
}
vaultSshPrivateKey = &targets.SessionCredential{
CredentialSource: &targets.CredentialSource{
Type: vaultGenericLibrarySubtype,
@@ -119,6 +139,17 @@ var (
},
}
staticPassword = &targets.SessionCredential{
CredentialSource: &targets.CredentialSource{
Type: staticSubtype,
},
Secret: &targets.SessionSecret{
Decoded: map[string]any{
"password": "static-decoded-pass",
},
},
}
staticSshPrivateKey = &targets.SessionCredential{
CredentialSource: &targets.CredentialSource{
Type: staticSubtype,
@@ -215,6 +246,21 @@ func Test_parseCredentials(t *testing.T) {
},
wantErr: false,
},
{
name: "password-typed",
creds: []*targets.SessionCredential{
typedPassword,
},
wantCreds: Credentials{
Password: []Password{
{
Password: "pass",
Raw: typedPassword,
},
},
},
wantErr: false,
},
{
name: "ssh-private-key-typed",
creds: []*targets.SessionCredential{
@@ -247,6 +293,21 @@ func Test_parseCredentials(t *testing.T) {
},
wantErr: false,
},
{
name: "vault-password-decoded",
creds: []*targets.SessionCredential{
vaultPassword,
},
wantCreds: Credentials{
Password: []Password{
{
Password: "vault-decoded-pass",
Raw: vaultPassword,
},
},
},
wantErr: false,
},
{
name: "vault-private-key-decoded",
creds: []*targets.SessionCredential{
@@ -343,6 +404,21 @@ func Test_parseCredentials(t *testing.T) {
},
wantErr: false,
},
{
name: "static-password-decoded",
creds: []*targets.SessionCredential{
staticPassword,
},
wantCreds: Credentials{
Password: []Password{
{
Password: "static-decoded-pass",
Raw: staticPassword,
},
},
},
wantErr: false,
},
{
name: "static-private-key-decoded",
creds: []*targets.SessionCredential{
@@ -388,7 +464,7 @@ func Test_parseCredentials(t *testing.T) {
creds: []*targets.SessionCredential{
staticSshPrivateKey, UnspecifiedCred1, vaultSshPrivateKey, typedUsernamePassword,
UnspecifiedCred, vaultUsernamePassword, typedSshPrivateKey, staticUsernamePassword,
staticKv,
staticKv, typedPassword, vaultPassword, staticPassword,
},
wantCreds: Credentials{
SshPrivateKey: []SshPrivateKey{
@@ -425,6 +501,20 @@ func Test_parseCredentials(t *testing.T) {
Raw: typedUsernamePassword,
},
},
Password: []Password{
{
Password: "static-decoded-pass",
Raw: staticPassword,
},
{
Password: "vault-decoded-pass",
Raw: vaultPassword,
},
{
Password: "pass",
Raw: typedPassword,
},
},
Unspecified: []*targets.SessionCredential{
UnspecifiedCred, UnspecifiedCred1, staticKv,
},
@@ -447,6 +537,7 @@ func Test_parseCredentials(t *testing.T) {
assert.ElementsMatch(tt.wantCreds.UsernamePassword, creds.UsernamePassword)
assert.ElementsMatch(tt.wantCreds.SshPrivateKey, creds.SshPrivateKey)
assert.ElementsMatch(tt.wantCreds.Unspecified, creds.Unspecified)
assert.ElementsMatch(tt.wantCreds.Password, creds.Password)
})
}
}
@@ -507,6 +598,29 @@ func Test_unconsumedSessionCredentials(t *testing.T) {
},
wantCreds: nil,
},
{
name: "p",
creds: Credentials{
Password: []Password{
{
Raw: vaultPassword,
},
},
},
wantCreds: []*targets.SessionCredential{vaultPassword},
},
{
name: "p-consumed",
creds: Credentials{
Password: []Password{
{
Raw: vaultPassword,
Consumed: true,
},
},
},
wantCreds: nil,
},
{
name: "Unspecified",
creds: Credentials{
@@ -542,10 +656,23 @@ func Test_unconsumedSessionCredentials(t *testing.T) {
Consumed: true,
},
},
Password: []Password{
{
Raw: staticPassword,
},
{
Raw: vaultPassword,
},
{
Raw: typedPassword,
Consumed: true,
},
},
Unspecified: []*targets.SessionCredential{UnspecifiedCred, UnspecifiedCred1},
},
wantCreds: []*targets.SessionCredential{
vaultSshPrivateKey, typedSshPrivateKey, vaultUsernamePassword, UnspecifiedCred, UnspecifiedCred1,
staticPassword, vaultPassword,
},
},
{
@@ -579,6 +706,20 @@ func Test_unconsumedSessionCredentials(t *testing.T) {
Consumed: true,
},
},
Password: []Password{
{
Raw: staticPassword,
Consumed: true,
},
{
Raw: vaultPassword,
Consumed: true,
},
{
Raw: typedPassword,
Consumed: true,
},
},
Unspecified: []*targets.SessionCredential{UnspecifiedCred, UnspecifiedCred1},
},
wantCreds: []*targets.SessionCredential{
@@ -610,11 +751,23 @@ func Test_unconsumedSessionCredentials(t *testing.T) {
Raw: typedUsernamePassword,
},
},
Password: []Password{
{
Raw: staticPassword,
},
{
Raw: vaultPassword,
},
{
Raw: typedPassword,
},
},
Unspecified: []*targets.SessionCredential{UnspecifiedCred, UnspecifiedCred1},
},
wantCreds: []*targets.SessionCredential{
staticSshPrivateKey, UnspecifiedCred1, vaultSshPrivateKey, typedUsernamePassword,
UnspecifiedCred, vaultUsernamePassword, typedSshPrivateKey, staticUsernamePassword,
staticPassword, vaultPassword, typedPassword,
},
},
}
@@ -0,0 +1,40 @@
// Code generated by "make api"; DO NOT EDIT.
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package sessionrecordings
import (
"fmt"
"github.com/mitchellh/mapstructure"
)
type PasswordCredentialAttributes struct {
PasswordHmac string `json:"password_hmac,omitempty"`
}
func AttributesMapToPasswordCredentialAttributes(in map[string]any) (*PasswordCredentialAttributes, error) {
if in == nil {
return nil, fmt.Errorf("nil input map")
}
var out PasswordCredentialAttributes
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
Result: &out,
TagName: "json",
})
if err != nil {
return nil, fmt.Errorf("error creating mapstructure decoder: %w", err)
}
if err := dec.Decode(in); err != nil {
return nil, fmt.Errorf("error decoding: %w", err)
}
return &out, nil
}
func (pt *Credential) GetPasswordCredentialAttributes() (*PasswordCredentialAttributes, error) {
if pt.Type != "password" {
return nil, fmt.Errorf("asked to fetch %s-type attributes but credential is of type %s", "password", pt.Type)
}
return AttributesMapToPasswordCredentialAttributes(pt.Attributes)
}