refact(vault): Create issuingCredentialLibrary Interface
Allows for new issuing credential library implementations in the future. Moved db and decrypt logic to privateCredentialLibraryAllTypes from issueCredentialLibrary. This also removes sessionId from retrieveCredential, it was not needed and removing allows retrieveCredential to be reused for credentials issued outside current workflow.
This commit is contained in:
1 parent
a15c5d80ce
commit
7833dd73c0
7 files changed
+338
-163
No files matched your search
@@ -1,10 +1,8 @@
|
||||
package vault
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/credential"
|
||||
"github.com/hashicorp/boundary/internal/credential/vault/store"
|
||||
"github.com/hashicorp/boundary/internal/db/sanitize"
|
||||
"github.com/hashicorp/boundary/internal/db/sentinel"
|
||||
@@ -46,14 +44,11 @@ type Credential struct {
|
||||
expiration time.Duration `gorm:"-"`
|
||||
}
|
||||
|
||||
func newCredential(libraryId, sessionId, externalId string, tokenHmac []byte, expiration time.Duration) (*Credential, error) {
|
||||
func newCredential(libraryId, externalId string, tokenHmac []byte, expiration time.Duration) (*Credential, error) {
|
||||
const op = "vault.newCredential"
|
||||
if libraryId == "" {
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "no library id")
|
||||
}
|
||||
if sessionId == "" {
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "no session id")
|
||||
}
|
||||
if len(tokenHmac) == 0 {
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "no tokenHmac")
|
||||
}
|
||||
@@ -69,7 +64,6 @@ func newCredential(libraryId, sessionId, externalId string, tokenHmac []byte, ex
|
||||
expiration: expiration.Round(time.Second),
|
||||
Credential: &store.Credential{
|
||||
LibraryId: libraryId,
|
||||
SessionId: sessionId,
|
||||
ExternalId: externalId,
|
||||
TokenHmac: tokenHmac,
|
||||
Status: status,
|
||||
@@ -117,38 +111,6 @@ func (c *Credential) oplog(op oplog.OpType) oplog.Metadata {
|
||||
return metadata
|
||||
}
|
||||
|
||||
func (c *Credential) insertQuery() (query string, queryValues []any) {
|
||||
queryValues = []any{
|
||||
sql.Named("public_id", c.PublicId),
|
||||
sql.Named("library_id", c.LibraryId),
|
||||
sql.Named("session_id", c.SessionId),
|
||||
sql.Named("token_hmac", c.TokenHmac),
|
||||
sql.Named("external_id", c.ExternalId),
|
||||
sql.Named("is_renewable", c.IsRenewable),
|
||||
sql.Named("status", c.Status),
|
||||
sql.Named("last_renewal_time", "now()"),
|
||||
}
|
||||
switch {
|
||||
case c.expiration == 0:
|
||||
query = insertCredentialWithInfiniteExpirationQuery
|
||||
default:
|
||||
query = insertCredentialWithExpirationQuery
|
||||
queryValues = append(queryValues, sql.Named("expiration_time", int(c.expiration.Round(time.Second).Seconds())))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Credential) updateSessionQuery(purpose credential.Purpose) (query string, queryValues []any) {
|
||||
queryValues = []any{
|
||||
sql.Named("public_id", c.PublicId),
|
||||
sql.Named("library_id", c.LibraryId),
|
||||
sql.Named("session_id", c.SessionId),
|
||||
sql.Named("purpose", string(purpose)),
|
||||
}
|
||||
query = updateSessionCredentialQuery
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Credential) updateExpirationQuery() (query string, queryValues []any) {
|
||||
queryValues = []any{
|
||||
int(c.expiration.Round(time.Second).Seconds()),
|
||||
|
||||
@@ -56,17 +56,6 @@ func TestCredential_New(t *testing.T) {
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "missing-session-id",
|
||||
args: args{
|
||||
libraryId: lib.GetPublicId(),
|
||||
externalId: "some/vault/credential",
|
||||
tokenHmac: token.GetTokenHmac(),
|
||||
expiration: 5 * time.Minute,
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "missing-tokenHmac",
|
||||
args: args{
|
||||
@@ -144,7 +133,7 @@ func TestCredential_New(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
ctx := context.Background()
|
||||
got, err := newCredential(tt.args.libraryId, tt.args.sessionId,
|
||||
got, err := newCredential(tt.args.libraryId,
|
||||
tt.args.externalId, tt.args.tokenHmac, tt.args.expiration)
|
||||
if tt.wantErr {
|
||||
assert.Error(err)
|
||||
@@ -162,7 +151,8 @@ func TestCredential_New(t *testing.T) {
|
||||
tt.want.PublicId = id
|
||||
got.PublicId = id
|
||||
|
||||
query, queryValues := got.insertQuery()
|
||||
query, queryValues := insertQuery(got, tt.args.sessionId)
|
||||
require.NoError(err)
|
||||
|
||||
rows, err2 := rw.Exec(ctx, query, queryValues)
|
||||
assert.Equal(1, rows)
|
||||
|
||||
@@ -25,7 +25,7 @@ var _ credential.Dynamic = (*baseCred)(nil)
|
||||
type baseCred struct {
|
||||
*Credential
|
||||
|
||||
lib *issueCredentialLibrary
|
||||
lib *genericIssuingCredentialLibrary
|
||||
secretData map[string]any
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ func (bc *baseCred) Secret() credential.SecretData { return bc.secretData }
|
||||
func (bc *baseCred) Library() credential.Library { return bc.lib }
|
||||
func (bc *baseCred) Purpose() credential.Purpose { return bc.lib.Purpose }
|
||||
func (bc *baseCred) getExpiration() time.Duration { return bc.expiration }
|
||||
func (bc *baseCred) getCredential() *Credential { return bc.Credential }
|
||||
|
||||
// convert converts bc to a specific credential type if bc is not
|
||||
// UnspecifiedType.
|
||||
@@ -132,12 +133,17 @@ func baseToSshPriKey(ctx context.Context, bc *baseCred) (*sshPrivateKeyCred, err
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ credential.Library = (*issueCredentialLibrary)(nil)
|
||||
var _ credential.Library = (*genericIssuingCredentialLibrary)(nil)
|
||||
|
||||
// A issueCredentialLibrary contains all the values needed to connect to Vault and
|
||||
type issuingCredentialLibrary interface {
|
||||
GetPublicId() string
|
||||
retrieveCredential(context.Context, errors.Op, ...credential.Option) (dynamicCred, error)
|
||||
}
|
||||
|
||||
// A genericIssuingCredentialLibrary contains all the values needed to connect to Vault and
|
||||
// retrieve credentials.
|
||||
type issueCredentialLibrary struct {
|
||||
PublicId string `gorm:"primary_key"`
|
||||
type genericIssuingCredentialLibrary struct {
|
||||
PublicId string
|
||||
StoreId string
|
||||
Name string
|
||||
Description string
|
||||
@@ -147,7 +153,7 @@ type issueCredentialLibrary struct {
|
||||
VaultPath string
|
||||
HttpMethod string
|
||||
HttpRequestBody []byte
|
||||
CredType string `gorm:"column:credential_type"`
|
||||
CredType string
|
||||
ProjectId string
|
||||
VaultAddress string
|
||||
Namespace string
|
||||
@@ -167,13 +173,13 @@ type issueCredentialLibrary struct {
|
||||
PasswordAttribute string
|
||||
PrivateKeyAttribute string
|
||||
PrivateKeyPassphraseAttribute string
|
||||
Purpose credential.Purpose `gorm:"-"`
|
||||
Purpose credential.Purpose
|
||||
}
|
||||
|
||||
func (pl *issueCredentialLibrary) clone() *issueCredentialLibrary {
|
||||
func (pl *genericIssuingCredentialLibrary) clone() *genericIssuingCredentialLibrary {
|
||||
// The 'append(a[:0:0], a...)' comes from
|
||||
// https://github.com/go101/go101/wiki/How-to-perfectly-clone-a-slice%3F
|
||||
return &issueCredentialLibrary{
|
||||
return &genericIssuingCredentialLibrary{
|
||||
PublicId: pl.PublicId,
|
||||
StoreId: pl.StoreId,
|
||||
CredType: pl.CredType,
|
||||
@@ -208,15 +214,15 @@ func (pl *issueCredentialLibrary) clone() *issueCredentialLibrary {
|
||||
}
|
||||
}
|
||||
|
||||
func (pl *issueCredentialLibrary) GetPublicId() string { return pl.PublicId }
|
||||
func (pl *issueCredentialLibrary) GetStoreId() string { return pl.StoreId }
|
||||
func (pl *issueCredentialLibrary) GetName() string { return pl.Name }
|
||||
func (pl *issueCredentialLibrary) GetDescription() string { return pl.Description }
|
||||
func (pl *issueCredentialLibrary) GetVersion() uint32 { return pl.Version }
|
||||
func (pl *issueCredentialLibrary) GetCreateTime() *timestamp.Timestamp { return pl.CreateTime }
|
||||
func (pl *issueCredentialLibrary) GetUpdateTime() *timestamp.Timestamp { return pl.UpdateTime }
|
||||
func (pl *genericIssuingCredentialLibrary) GetPublicId() string { return pl.PublicId }
|
||||
func (pl *genericIssuingCredentialLibrary) GetStoreId() string { return pl.StoreId }
|
||||
func (pl *genericIssuingCredentialLibrary) GetName() string { return pl.Name }
|
||||
func (pl *genericIssuingCredentialLibrary) GetDescription() string { return pl.Description }
|
||||
func (pl *genericIssuingCredentialLibrary) GetVersion() uint32 { return pl.Version }
|
||||
func (pl *genericIssuingCredentialLibrary) GetCreateTime() *timestamp.Timestamp { return pl.CreateTime }
|
||||
func (pl *genericIssuingCredentialLibrary) GetUpdateTime() *timestamp.Timestamp { return pl.UpdateTime }
|
||||
|
||||
func (pl *issueCredentialLibrary) CredentialType() credential.Type {
|
||||
func (pl *genericIssuingCredentialLibrary) CredentialType() credential.Type {
|
||||
switch ct := pl.CredType; ct {
|
||||
case "":
|
||||
return credential.UnspecifiedType
|
||||
@@ -225,41 +231,8 @@ func (pl *issueCredentialLibrary) CredentialType() credential.Type {
|
||||
}
|
||||
}
|
||||
|
||||
func (pl *issueCredentialLibrary) decrypt(ctx context.Context, cipher wrapping.Wrapper) error {
|
||||
const op = "vault.(issueCredentialLibrary).decrypt"
|
||||
|
||||
if pl.CtToken != nil {
|
||||
type ptk struct {
|
||||
Token []byte `wrapping:"pt,token_data"`
|
||||
CtToken []byte `wrapping:"ct,token_data"`
|
||||
}
|
||||
ptkv := &ptk{
|
||||
CtToken: pl.CtToken,
|
||||
}
|
||||
if err := structwrapping.UnwrapStruct(ctx, cipher, ptkv, nil); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithCode(errors.Decrypt), errors.WithMsg("token"))
|
||||
}
|
||||
pl.Token = ptkv.Token
|
||||
}
|
||||
|
||||
if pl.CtClientKey != nil && pl.ClientCert != nil {
|
||||
type pck struct {
|
||||
Key []byte `wrapping:"pt,key_data"`
|
||||
CtKey []byte `wrapping:"ct,key_data"`
|
||||
}
|
||||
pckv := &pck{
|
||||
CtKey: pl.CtClientKey,
|
||||
}
|
||||
if err := structwrapping.UnwrapStruct(ctx, cipher, pckv, nil); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithCode(errors.Decrypt), errors.WithMsg("client certificate"))
|
||||
}
|
||||
pl.ClientKey = pckv.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pl *issueCredentialLibrary) client(ctx context.Context) (vaultClient, error) {
|
||||
const op = "vault.(issueCredentialLibrary).client"
|
||||
func (pl *genericIssuingCredentialLibrary) client(ctx context.Context) (vaultClient, error) {
|
||||
const op = "vault.(genericIssuingCredentialLibrary).client"
|
||||
clientConfig := &clientConfig{
|
||||
Addr: pl.VaultAddress,
|
||||
Token: pl.Token,
|
||||
@@ -284,15 +257,14 @@ func (pl *issueCredentialLibrary) client(ctx context.Context) (vaultClient, erro
|
||||
type dynamicCred interface {
|
||||
credential.Dynamic
|
||||
getExpiration() time.Duration
|
||||
insertQuery() (query string, queryValues []any)
|
||||
updateSessionQuery(purpose credential.Purpose) (query string, queryValues []any)
|
||||
getCredential() *Credential
|
||||
}
|
||||
|
||||
// retrieveCredential retrieves a dynamic credential from Vault for the
|
||||
// given sessionId.
|
||||
//
|
||||
// Supported options: credential.WithTemplateData
|
||||
func (pl *issueCredentialLibrary) retrieveCredential(ctx context.Context, op errors.Op, sessionId string, opt ...credential.Option) (dynamicCred, error) {
|
||||
func (pl *genericIssuingCredentialLibrary) retrieveCredential(ctx context.Context, op errors.Op, opt ...credential.Option) (dynamicCred, error) {
|
||||
opts, err := credential.GetOpts(opt...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
@@ -358,7 +330,7 @@ func (pl *issueCredentialLibrary) retrieveCredential(ctx context.Context, op err
|
||||
}
|
||||
|
||||
leaseDuration := time.Duration(secret.LeaseDuration) * time.Second
|
||||
cred, err := newCredential(pl.GetPublicId(), sessionId, secret.LeaseID, pl.TokenHmac, leaseDuration)
|
||||
cred, err := newCredential(pl.GetPublicId(), secret.LeaseID, pl.TokenHmac, leaseDuration)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
@@ -374,11 +346,11 @@ func (pl *issueCredentialLibrary) retrieveCredential(ctx context.Context, op err
|
||||
}
|
||||
|
||||
// TableName returns the table name for gorm.
|
||||
func (pl *issueCredentialLibrary) TableName() string {
|
||||
func (pl *genericIssuingCredentialLibrary) TableName() string {
|
||||
return "credential_vault_library_issue_credentials"
|
||||
}
|
||||
|
||||
func (r *Repository) getIssueCredLibraries(ctx context.Context, requests []credential.Request) ([]*issueCredentialLibrary, error) {
|
||||
func (r *Repository) getIssueCredLibraries(ctx context.Context, requests []credential.Request) ([]issuingCredentialLibrary, error) {
|
||||
const op = "vault.(Repository).getIssueCredLibraries"
|
||||
|
||||
mapper, err := newMapper(requests)
|
||||
@@ -405,9 +377,9 @@ func (r *Repository) getIssueCredLibraries(ctx context.Context, requests []crede
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var libs []*issueCredentialLibrary
|
||||
var libs []*privateCredentialLibraryAllTypes
|
||||
for rows.Next() {
|
||||
var lib issueCredentialLibrary
|
||||
var lib privateCredentialLibraryAllTypes
|
||||
if err := r.reader.ScanRows(ctx, rows, &lib); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("scan row failed"))
|
||||
}
|
||||
@@ -422,6 +394,7 @@ func (r *Repository) getIssueCredLibraries(ctx context.Context, requests []crede
|
||||
}
|
||||
}
|
||||
|
||||
var decryptedLibs []issuingCredentialLibrary
|
||||
for _, pl := range libs {
|
||||
databaseWrapper, err := r.kms.GetWrapper(ctx, pl.ProjectId, kms.KeyPurposeDatabase)
|
||||
if err != nil {
|
||||
@@ -431,9 +404,155 @@ func (r *Repository) getIssueCredLibraries(ctx context.Context, requests []crede
|
||||
if err := pl.decrypt(ctx, databaseWrapper); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
decryptedLibs = append(decryptedLibs, pl.toTypedIssuingCredentialLibrary())
|
||||
}
|
||||
|
||||
return libs, nil
|
||||
return decryptedLibs, nil
|
||||
}
|
||||
|
||||
// privateCredentialLibraryAllTypes is a clone of genericIssuingCredentialLibrary. Contains
|
||||
// all the values needed to connect to Vault and retrieve credentials.
|
||||
type privateCredentialLibraryAllTypes struct {
|
||||
PublicId string `gorm:"primary_key"`
|
||||
StoreId string
|
||||
Name string
|
||||
Description string
|
||||
CreateTime *timestamp.Timestamp
|
||||
UpdateTime *timestamp.Timestamp
|
||||
Version uint32
|
||||
VaultPath string
|
||||
HttpMethod string
|
||||
HttpRequestBody []byte
|
||||
CredType string `gorm:"column:credential_type"`
|
||||
ProjectId string
|
||||
VaultAddress string
|
||||
Namespace string
|
||||
CaCert []byte
|
||||
TlsServerName string
|
||||
TlsSkipVerify bool
|
||||
WorkerFilter string
|
||||
Token TokenSecret
|
||||
CtToken []byte
|
||||
TokenHmac []byte
|
||||
TokenKeyId string
|
||||
ClientCert []byte
|
||||
ClientKey KeySecret
|
||||
CtClientKey []byte
|
||||
ClientKeyId string
|
||||
UsernameAttribute string
|
||||
PasswordAttribute string
|
||||
PrivateKeyAttribute string
|
||||
PrivateKeyPassphraseAttribute string
|
||||
Purpose credential.Purpose `gorm:"-"`
|
||||
}
|
||||
|
||||
func (pl *privateCredentialLibraryAllTypes) GetPublicId() string { return pl.PublicId }
|
||||
|
||||
func (pl *privateCredentialLibraryAllTypes) decrypt(ctx context.Context, cipher wrapping.Wrapper) error {
|
||||
const op = "vault.(privateCredentialLibraryAllTypes).decrypt"
|
||||
|
||||
if pl.CtToken != nil {
|
||||
type ptk struct {
|
||||
Token []byte `wrapping:"pt,token_data"`
|
||||
CtToken []byte `wrapping:"ct,token_data"`
|
||||
}
|
||||
ptkv := &ptk{
|
||||
CtToken: pl.CtToken,
|
||||
}
|
||||
if err := structwrapping.UnwrapStruct(ctx, cipher, ptkv, nil); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithCode(errors.Decrypt), errors.WithMsg("token"))
|
||||
}
|
||||
pl.Token = ptkv.Token
|
||||
}
|
||||
|
||||
if pl.CtClientKey != nil && pl.ClientCert != nil {
|
||||
type pck struct {
|
||||
Key []byte `wrapping:"pt,key_data"`
|
||||
CtKey []byte `wrapping:"ct,key_data"`
|
||||
}
|
||||
pckv := &pck{
|
||||
CtKey: pl.CtClientKey,
|
||||
}
|
||||
if err := structwrapping.UnwrapStruct(ctx, cipher, pckv, nil); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithCode(errors.Decrypt), errors.WithMsg("client certificate"))
|
||||
}
|
||||
pl.ClientKey = pckv.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pl *privateCredentialLibraryAllTypes) clone() *privateCredentialLibraryAllTypes {
|
||||
// The 'append(a[:0:0], a...)' comes from
|
||||
// https://github.com/go101/go101/wiki/How-to-perfectly-clone-a-slice%3F
|
||||
return &privateCredentialLibraryAllTypes{
|
||||
PublicId: pl.PublicId,
|
||||
StoreId: pl.StoreId,
|
||||
CredType: pl.CredType,
|
||||
UsernameAttribute: pl.UsernameAttribute,
|
||||
PasswordAttribute: pl.PasswordAttribute,
|
||||
PrivateKeyAttribute: pl.PrivateKeyAttribute,
|
||||
PrivateKeyPassphraseAttribute: pl.PrivateKeyPassphraseAttribute,
|
||||
Name: pl.Name,
|
||||
Description: pl.Description,
|
||||
CreateTime: proto.Clone(pl.CreateTime).(*timestamp.Timestamp),
|
||||
UpdateTime: proto.Clone(pl.UpdateTime).(*timestamp.Timestamp),
|
||||
Version: pl.Version,
|
||||
ProjectId: pl.ProjectId,
|
||||
VaultPath: pl.VaultPath,
|
||||
HttpMethod: pl.HttpMethod,
|
||||
HttpRequestBody: append(pl.HttpRequestBody[:0:0], pl.HttpRequestBody...),
|
||||
VaultAddress: pl.VaultAddress,
|
||||
Namespace: pl.Namespace,
|
||||
CaCert: append(pl.CaCert[:0:0], pl.CaCert...),
|
||||
TlsServerName: pl.TlsServerName,
|
||||
TlsSkipVerify: pl.TlsSkipVerify,
|
||||
WorkerFilter: pl.WorkerFilter,
|
||||
TokenHmac: append(pl.TokenHmac[:0:0], pl.TokenHmac...),
|
||||
Token: append(pl.Token[:0:0], pl.Token...),
|
||||
CtToken: append(pl.CtToken[:0:0], pl.CtToken...),
|
||||
TokenKeyId: pl.TokenKeyId,
|
||||
ClientCert: append(pl.ClientCert[:0:0], pl.ClientCert...),
|
||||
ClientKey: append(pl.ClientKey[:0:0], pl.ClientKey...),
|
||||
CtClientKey: append(pl.CtClientKey[:0:0], pl.CtClientKey...),
|
||||
ClientKeyId: pl.ClientKeyId,
|
||||
Purpose: pl.Purpose,
|
||||
}
|
||||
}
|
||||
|
||||
func (pl *privateCredentialLibraryAllTypes) toTypedIssuingCredentialLibrary() issuingCredentialLibrary {
|
||||
return &genericIssuingCredentialLibrary{
|
||||
PublicId: pl.PublicId,
|
||||
StoreId: pl.StoreId,
|
||||
CredType: pl.CredType,
|
||||
UsernameAttribute: pl.UsernameAttribute,
|
||||
PasswordAttribute: pl.PasswordAttribute,
|
||||
PrivateKeyAttribute: pl.PrivateKeyAttribute,
|
||||
PrivateKeyPassphraseAttribute: pl.PrivateKeyPassphraseAttribute,
|
||||
Name: pl.Name,
|
||||
Description: pl.Description,
|
||||
CreateTime: pl.CreateTime,
|
||||
UpdateTime: pl.UpdateTime,
|
||||
Version: pl.Version,
|
||||
ProjectId: pl.ProjectId,
|
||||
VaultPath: pl.VaultPath,
|
||||
HttpMethod: pl.HttpMethod,
|
||||
HttpRequestBody: pl.HttpRequestBody,
|
||||
VaultAddress: pl.VaultAddress,
|
||||
Namespace: pl.Namespace,
|
||||
CaCert: pl.CaCert,
|
||||
TlsServerName: pl.TlsServerName,
|
||||
TlsSkipVerify: pl.TlsSkipVerify,
|
||||
WorkerFilter: pl.WorkerFilter,
|
||||
TokenHmac: pl.TokenHmac,
|
||||
Token: pl.Token,
|
||||
CtToken: pl.CtToken,
|
||||
TokenKeyId: pl.TokenKeyId,
|
||||
ClientCert: pl.ClientCert,
|
||||
ClientKey: pl.ClientKey,
|
||||
CtClientKey: pl.CtClientKey,
|
||||
ClientKeyId: pl.ClientKeyId,
|
||||
Purpose: pl.Purpose,
|
||||
}
|
||||
}
|
||||
|
||||
// requestMap takes a slice of credential requests and provides of list of
|
||||
|
||||
@@ -269,7 +269,10 @@ func TestRepository_getPrivateLibraries(t *testing.T) {
|
||||
require.NotNil(gotLibs)
|
||||
assert.Len(gotLibs, len(libs))
|
||||
|
||||
for _, got := range gotLibs {
|
||||
for _, gotLib := range gotLibs {
|
||||
got, ok := gotLib.(*genericIssuingCredentialLibrary)
|
||||
require.True(ok)
|
||||
|
||||
assert.Equal(TokenSecret(token), got.Token)
|
||||
if tt.tls == TestClientTLS {
|
||||
require.NotNil(got.ClientKey)
|
||||
@@ -414,7 +417,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "library-not-username-password-type",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UnspecifiedType),
|
||||
},
|
||||
},
|
||||
@@ -423,7 +426,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "invalid-no-username-default-password-attribute",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -435,7 +438,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "invalid-no-password-default-username-attribute",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -447,7 +450,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "valid-default-attributes",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -463,7 +466,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "valid-override-attributes",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
UsernameAttribute: "test-username",
|
||||
PasswordAttribute: "test-password",
|
||||
@@ -483,7 +486,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "valid-default-username-override-password",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
PasswordAttribute: "test-password",
|
||||
},
|
||||
@@ -502,7 +505,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "valid-override-username-default-password",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
UsernameAttribute: "test-username",
|
||||
},
|
||||
@@ -521,7 +524,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "invalid-username-override",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
UsernameAttribute: "missing-username",
|
||||
},
|
||||
@@ -537,7 +540,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "invalid-password-override",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
UsernameAttribute: "missing-password",
|
||||
},
|
||||
@@ -553,7 +556,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-no-metadata-field",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -568,7 +571,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-no-data-field",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -580,7 +583,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-no-username-default-password-attribute",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -595,7 +598,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-no-passsword-default-username-attribute",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -610,7 +613,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-invalid-metadata-type",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -626,7 +629,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-invalid-metadata-type",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -639,7 +642,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-additional-field",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -656,7 +659,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "valid-kv2-default-attributes",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -675,7 +678,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "valid-kv2-override-attributes",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
UsernameAttribute: "test-username",
|
||||
PasswordAttribute: "test-password",
|
||||
@@ -698,7 +701,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "valid-kv2-default-username-override-password",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
PasswordAttribute: "test-password",
|
||||
},
|
||||
@@ -720,7 +723,7 @@ func TestBaseToUsrPass(t *testing.T) {
|
||||
{
|
||||
name: "valid-kv2-override-username-default-password",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UsernamePasswordType),
|
||||
UsernameAttribute: "test-username",
|
||||
},
|
||||
@@ -779,7 +782,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "library-not-ssh-private-key-type",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.UnspecifiedType),
|
||||
},
|
||||
},
|
||||
@@ -788,7 +791,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "invalid-no-username-default-pk-attribute",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -800,7 +803,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "invalid-no-pk-default-username-attribute",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -812,7 +815,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "valid-default-attributes",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -828,7 +831,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "valid-default-attributes-with-passphrase",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -846,7 +849,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "valid-override-attributes",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
UsernameAttribute: "test-username",
|
||||
PrivateKeyAttribute: "test-pk",
|
||||
@@ -866,7 +869,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "valid-override-attributes-with-passphrase",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
UsernameAttribute: "test-username",
|
||||
PrivateKeyAttribute: "test-pk",
|
||||
@@ -890,7 +893,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "valid-default-username-override-pk",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
PrivateKeyAttribute: "test-pk",
|
||||
},
|
||||
@@ -909,7 +912,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "valid-override-username-default-pk",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
UsernameAttribute: "test-username",
|
||||
},
|
||||
@@ -928,7 +931,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "invalid-username-override",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
UsernameAttribute: "missing-username",
|
||||
},
|
||||
@@ -944,7 +947,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "invalid-pk-override",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
UsernameAttribute: "missing-pk",
|
||||
},
|
||||
@@ -960,7 +963,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-no-metadata-field",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -975,7 +978,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-no-data-field",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -987,7 +990,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-no-username-default-pk-attribute",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -1002,7 +1005,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-no-pk-default-username-attribute",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -1017,7 +1020,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-invalid-metadata-type",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -1033,7 +1036,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-invalid-data-type",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -1046,7 +1049,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "invalid-kv2-additional-field",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -1063,7 +1066,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "valid-kv2-default-attributes",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -1082,7 +1085,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "valid-kv2-default-attributes-with-passphrase",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
},
|
||||
secretData: map[string]any{
|
||||
@@ -1103,7 +1106,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "valid-kv2-override-attributes",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
UsernameAttribute: "test-username",
|
||||
PrivateKeyAttribute: "test-pk",
|
||||
@@ -1126,7 +1129,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "valid-kv2-override-attributes-with-passphrase",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
UsernameAttribute: "test-username",
|
||||
PrivateKeyAttribute: "test-pk",
|
||||
@@ -1153,7 +1156,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "valid-kv2-default-username-override-pk",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
PrivateKeyAttribute: "test-pk",
|
||||
},
|
||||
@@ -1175,7 +1178,7 @@ func TestBaseToSshPriKey(t *testing.T) {
|
||||
{
|
||||
name: "valid-kv2-override-username-default-pk",
|
||||
given: &baseCred{
|
||||
lib: &issueCredentialLibrary{
|
||||
lib: &genericIssuingCredentialLibrary{
|
||||
CredType: string(credential.SshPrivateKeyType),
|
||||
UsernameAttribute: "test-username",
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ package vault
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -13,6 +14,38 @@ import (
|
||||
|
||||
var _ credential.Issuer = (*Repository)(nil)
|
||||
|
||||
func insertQuery(c *Credential, sessionId string) (query string, queryValues []any) {
|
||||
queryValues = []any{
|
||||
sql.Named("public_id", c.PublicId),
|
||||
sql.Named("library_id", c.LibraryId),
|
||||
sql.Named("session_id", sessionId),
|
||||
sql.Named("token_hmac", c.TokenHmac),
|
||||
sql.Named("external_id", c.ExternalId),
|
||||
sql.Named("is_renewable", c.IsRenewable),
|
||||
sql.Named("status", c.Status),
|
||||
sql.Named("last_renewal_time", "now()"),
|
||||
}
|
||||
switch {
|
||||
case c.expiration == 0:
|
||||
query = insertCredentialWithInfiniteExpirationQuery
|
||||
default:
|
||||
query = insertCredentialWithExpirationQuery
|
||||
queryValues = append(queryValues, sql.Named("expiration_time", int(c.expiration.Round(time.Second).Seconds())))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func updateSessionQuery(c *Credential, sessionId string, purpose credential.Purpose) (query string, queryValues []any) {
|
||||
queryValues = []any{
|
||||
sql.Named("public_id", c.PublicId),
|
||||
sql.Named("library_id", c.LibraryId),
|
||||
sql.Named("session_id", sessionId),
|
||||
sql.Named("purpose", string(purpose)),
|
||||
}
|
||||
query = updateSessionCredentialQuery
|
||||
return
|
||||
}
|
||||
|
||||
// Issue issues and returns dynamic credentials from Vault for all of the
|
||||
// requests and assigns them to sessionId.
|
||||
func (r *Repository) Issue(ctx context.Context, sessionId string, requests []credential.Request, opt ...credential.Option) ([]credential.Dynamic, error) {
|
||||
@@ -37,7 +70,7 @@ func (r *Repository) Issue(ctx context.Context, sessionId string, requests []cre
|
||||
var minLease time.Duration
|
||||
runJobsInterval := r.scheduler.GetRunJobsInterval()
|
||||
for _, lib := range libs {
|
||||
cred, err := lib.retrieveCredential(ctx, op, sessionId, opt...)
|
||||
cred, err := lib.retrieveCredential(ctx, op, opt...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -54,8 +87,18 @@ func (r *Repository) Issue(ctx context.Context, sessionId string, requests []cre
|
||||
if minLease > cred.getExpiration() {
|
||||
minLease = cred.getExpiration()
|
||||
}
|
||||
insertQuery, insertQueryValues := cred.insertQuery()
|
||||
updateQuery, updateQueryValues := cred.updateSessionQuery(lib.Purpose)
|
||||
|
||||
underlyingCred := cred.getCredential()
|
||||
|
||||
insertQuery, insertQueryValues := insertQuery(underlyingCred, sessionId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updateQuery, updateQueryValues := updateSessionQuery(underlyingCred, sessionId, cred.Purpose())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := r.writer.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{},
|
||||
func(_ db.Reader, w db.Writer) error {
|
||||
rowsInserted, err := w.Exec(ctx, insertQuery, insertQueryValues)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/credential"
|
||||
"github.com/hashicorp/boundary/internal/credential/vault"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/db/timestamp"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/host/static"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
@@ -21,6 +22,58 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// since we're not using gorm tags to retrieve this, it's faster and easier to just make a new struct than import usrPassCred from the vault package
|
||||
type userPassCred struct {
|
||||
PublicId string
|
||||
LibraryId string
|
||||
SessionId string
|
||||
TokenHmac []byte
|
||||
ExternalId string
|
||||
IsRenewable bool
|
||||
Status string
|
||||
LastRenewalTime *timestamp.Timestamp
|
||||
ExpirationTime *timestamp.Timestamp
|
||||
}
|
||||
|
||||
func lookupDbCred(t *testing.T, ctx context.Context, rw *db.Db, upc credential.UsernamePassword) userPassCred {
|
||||
rows, err := rw.Query(ctx, `
|
||||
select
|
||||
public_id,
|
||||
library_id,
|
||||
session_id,
|
||||
token_hmac,
|
||||
external_id,
|
||||
is_renewable,
|
||||
status,
|
||||
last_renewal_time,
|
||||
expiration_time
|
||||
from credential_vault_credential
|
||||
where public_id = ?;
|
||||
`, []any{upc.GetPublicId()})
|
||||
require.NoError(t, err)
|
||||
rowCount := 0
|
||||
|
||||
got := userPassCred{}
|
||||
|
||||
for rows.Next() {
|
||||
rowCount++
|
||||
require.NoError(t, rows.Scan(
|
||||
&got.PublicId,
|
||||
&got.LibraryId,
|
||||
&got.SessionId,
|
||||
&got.TokenHmac,
|
||||
&got.ExternalId,
|
||||
&got.IsRenewable,
|
||||
&got.Status,
|
||||
&got.LastRenewalTime,
|
||||
&got.ExpirationTime,
|
||||
))
|
||||
}
|
||||
assert.Equal(t, 1, rowCount)
|
||||
|
||||
return got
|
||||
}
|
||||
|
||||
func TestRepository_IssueCredentials(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
@@ -398,6 +451,11 @@ func TestRepository_IssueCredentials(t *testing.T) {
|
||||
if upc, ok := dc.(credential.UsernamePassword); ok {
|
||||
assert.NotEmpty(upc.Username())
|
||||
assert.NotEmpty(upc.Password())
|
||||
// we also want to retrieve the cred from the db and make sure it's the same as the one returned by Issue
|
||||
retrieved := lookupDbCred(t, ctx, rw, upc)
|
||||
require.Equal(retrieved.SessionId, sess.GetPublicId())
|
||||
require.Equal(retrieved.PublicId, upc.GetPublicId())
|
||||
// these asserts are super basic because the main check we want is that lookupDbCred succeeded
|
||||
break
|
||||
}
|
||||
assert.Fail("want UsernamePassword credential from library with credential type UsernamePassword")
|
||||
|
||||
@@ -168,7 +168,7 @@ func TestCredentials(t testing.TB, conn *db.DB, wrapper wrapping.Wrapper, librar
|
||||
|
||||
var credentials []*Credential
|
||||
for i := 0; i < count; i++ {
|
||||
credential, err := newCredential(lib.GetPublicId(), sessionId, fmt.Sprintf("vault/credential/%d", i), token.GetTokenHmac(), 5*time.Minute)
|
||||
credential, err := newCredential(lib.GetPublicId(), fmt.Sprintf("vault/credential/%d", i), token.GetTokenHmac(), 5*time.Minute)
|
||||
assert.NoError(err)
|
||||
require.NotNil(credential)
|
||||
|
||||
@@ -177,7 +177,7 @@ func TestCredentials(t testing.TB, conn *db.DB, wrapper wrapping.Wrapper, librar
|
||||
require.NotNil(id)
|
||||
credential.PublicId = id
|
||||
|
||||
query, queryValues := credential.insertQuery()
|
||||
query, queryValues := insertQuery(credential, sessionId)
|
||||
rows, err2 := rw.Exec(ctx, query, queryValues)
|
||||
assert.Equal(1, rows)
|
||||
assert.NoError(err2)
|
||||
|
||||
Reference in new issue
Block a user