Merge branch 'tmessi-target-egress' (#1594)

This commit is contained in:
Timothy Messier committed 2021-10-29 10:30:27 -04:00
commit 66a1b996d0
22 files changed
+1413 -182

No files matched your search

+1
View File
@@ -129,6 +129,7 @@ protobuild:
@protoc-go-inject-tag -input=./internal/kms/store/session_key.pb.go
@protoc-go-inject-tag -input=./internal/kms/store/oidc_key.pb.go
@protoc-go-inject-tag -input=./internal/target/store/target.pb.go
@protoc-go-inject-tag -input=./internal/target/targettest/store/target.pb.go
@protoc-go-inject-tag -input=./internal/target/tcp/store/target.pb.go
@protoc-go-inject-tag -input=./internal/auth/oidc/store/oidc.pb.go
@protoc-go-inject-tag -input=./internal/scheduler/job/store/job.pb.go
+11
View File
@@ -28,6 +28,10 @@ type Library interface {
// Purpose is the purpose of the credential.
type Purpose string
func (p Purpose) String() string {
return string(p)
}
// Credential purpose values.
const (
// ApplicationPurpose is a credential used for application specific
@@ -45,6 +49,13 @@ const (
EgressPurpose Purpose = "egress"
)
// ValidPurposes are the set of all credential Purposes.
var ValidPurposes = []Purpose{
ApplicationPurpose,
IngressPurpose,
EgressPurpose,
}
// SecretData represents secret data.
type SecretData interface{}
@@ -165,16 +165,19 @@ func testSessionCredentialParams(t *testing.T, conn *db.DB, kms *kms.Kms, wrappe
ctx := context.Background()
stores := vault.TestCredentialStores(t, conn, wrapper, tar.GetScopeId(), 1)
libs := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2)
libIds := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2)
libs := []*target.CredentialLibrary{
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.ApplicationPurpose),
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), credential.ApplicationPurpose),
}
targetRepo, err := target.NewRepository(rw, rw, kms)
require.NoError(t, err)
_, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tar.GetPublicId(), tar.GetVersion(), []string{libs[0].PublicId, libs[1].PublicId})
_, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tar.GetPublicId(), tar.GetVersion(), libs)
require.NoError(t, err)
creds := []*session.DynamicCredential{
session.NewDynamicCredential(libs[0].GetPublicId(), credential.ApplicationPurpose),
session.NewDynamicCredential(libs[0].GetPublicId(), credential.IngressPurpose),
session.NewDynamicCredential(libs[1].GetPublicId(), credential.EgressPurpose),
session.NewDynamicCredential(libIds[0].GetPublicId(), credential.ApplicationPurpose),
session.NewDynamicCredential(libIds[1].GetPublicId(), credential.ApplicationPurpose),
}
return creds
}
@@ -0,0 +1,73 @@
syntax = "proto3";
package controller.storage.target.targettest.store.v1;
option go_package = "github.com/hashicorp/boundary/internal/target/targettest/store;store";
import "controller/storage/timestamp/v1/timestamp.proto";
import "controller/custom_options/v1/options.proto";
message Target {
// public_id is used to access the targettest.Target via an API
// @inject_tag: gorm:"primary_key"
string public_id = 10;
// scope id for the targettest.Target
// @inject_tag: `gorm:"default:null"`
string scope_id = 20;
// name is the optional friendly name used to
// access the targettest.Target via an API
// @inject_tag: `gorm:"default:null"`
string name = 30
[(custom_options.v1.mask_mapping) = { this: "name" that: "name" }];
// description of the targettest.Target
// @inject_tag: `gorm:"default:null"`
string description = 40 [(custom_options.v1.mask_mapping) = {
this: "description"
that: "description"
}];
// create_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
timestamp.v1.Timestamp create_time = 50;
// update_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
timestamp.v1.Timestamp update_time = 60;
// version allows optimistic locking of the targettest.Target when modifying the
// targettest.Target
// @inject_tag: `gorm:"default:null"`
uint32 version = 70;
// default port of the targettest.Target
// @inject_tag: `gorm:"default:null"`
uint32 default_port = 80 [(custom_options.v1.mask_mapping) = {
this: "DefaultPort"
that: "attributes.default_port"
}];
// Maximum total lifetime of a created session, in seconds
// @inject_tag: `gorm:"default:null"`
uint32 session_max_seconds = 100 [(custom_options.v1.mask_mapping) = {
this: "SessionMaxSeconds"
that: "session_max_seconds"
}];
// Maximum number of connections in a session
// @inject_tag: `gorm:"default:null"`
int32 session_connection_limit = 110 [(custom_options.v1.mask_mapping) = {
this: "SessionConnectionLimit"
that: "session_connection_limit"
}];
// A boolean expression that allows filtering the workers that can handle a session
// @inject_tag: `gorm:"default:null"`
string worker_filter = 120 [(custom_options.v1.mask_mapping) = {
this: "WorkerFilter"
that: "worker_filter"
}];
}
@@ -1346,12 +1346,17 @@ func (s Service) removeHostSourcesInRepo(ctx context.Context, targetId string, h
return out, hs, cl, nil
}
func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string, ids []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) {
func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) {
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
}
out, hs, credSources, err := repo.AddTargetCredentialSources(ctx, targetId, version, strutil.RemoveDuplicates(ids, false))
credLibs, err := createCredLibs(targetId, applicationIds, nil, nil)
if err != nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err)
}
out, hs, credSources, err := repo.AddTargetCredentialSources(ctx, targetId, version, credLibs)
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to add credential sources to target: %v.", err)
@@ -1362,13 +1367,19 @@ func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string
return out, hs, credSources, nil
}
func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string, ids []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) {
func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) {
const op = "targets.(Service).setCredentialSourcesInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
}
_, _, _, err = repo.SetTargetCredentialSources(ctx, targetId, version, strutil.RemoveDuplicates(ids, false))
credLibs, err := createCredLibs(targetId, applicationIds, nil, nil)
if err != nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err)
}
_, _, _, err = repo.SetTargetCredentialSources(ctx, targetId, version, credLibs)
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err)
@@ -1384,13 +1395,18 @@ func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string
return out, hs, credSources, nil
}
func (s Service) removeCredentialSourcesInRepo(ctx context.Context, targetId string, ids []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) {
func (s Service) removeCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) {
const op = "targets.(Service).removeCredentialSourcesInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
}
_, err = repo.DeleteTargetCredentialSources(ctx, targetId, version, strutil.RemoveDuplicates(ids, false))
credLibs, err := createCredLibs(targetId, applicationIds, nil, nil)
if err != nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err)
}
_, err = repo.DeleteTargetCredentialSources(ctx, targetId, version, credLibs)
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to remove credential sources from target: %v.", err)
@@ -2003,3 +2019,23 @@ func validateAuthorizeSessionRequest(req *pbs.AuthorizeSessionRequest) error {
}
return nil
}
func createCredLibs(targetId string, applicationIds, ingressIds, egressIds []string) ([]*target.CredentialLibrary, error) {
credLibs := make([]*target.CredentialLibrary, 0, len(applicationIds)+len(ingressIds)+len(egressIds))
byPurpose := map[credential.Purpose][]string{
credential.ApplicationPurpose: strutil.RemoveDuplicates(applicationIds, false),
credential.IngressPurpose: strutil.RemoveDuplicates(ingressIds, false),
credential.EgressPurpose: strutil.RemoveDuplicates(egressIds, false),
}
for purpose, ids := range byPurpose {
for _, id := range ids {
l, err := target.NewCredentialLibrary(targetId, id, purpose)
if err != nil {
return nil, err
}
credLibs = append(credLibs, l)
}
}
return credLibs, nil
}
@@ -14,6 +14,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/credential/vault"
"github.com/hashicorp/boundary/internal/db"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
@@ -1704,13 +1705,13 @@ func TestAddTargetLibraries(t *testing.T) {
},
{
name: "Add library on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for libraries", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for libraries", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
addLibraries: []string{cls[1].GetPublicId()},
resultLibraryIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
},
{
name: "Add duplicated libraries on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for libraries", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for libraries", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
addLibraries: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
resultLibraryIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
},
@@ -1840,19 +1841,19 @@ func TestSetTargetLibraries(t *testing.T) {
},
{
name: "Set on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setLibraries: []string{cls[1].GetPublicId()},
resultLibraryIds: []string{cls[1].GetPublicId()},
},
{
name: "Set duplicate libraries on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setLibraries: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
resultLibraryIds: []string{cls[1].GetPublicId()},
},
{
name: "Set empty on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setLibraries: []string{},
resultLibraryIds: nil,
},
@@ -1966,13 +1967,13 @@ func TestRemoveTargetLibraries(t *testing.T) {
},
{
name: "Remove 1 of 2 libraries",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
removeLibs: []string{cls[1].GetPublicId()},
resultLibIds: []string{cls[0].GetPublicId()},
},
{
name: "Remove 1 duplicate set of 2 libraries",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
removeLibs: []string{
cls[1].GetPublicId(), cls[1].GetPublicId(),
},
@@ -1980,7 +1981,7 @@ func TestRemoveTargetLibraries(t *testing.T) {
},
{
name: "Remove all libraries from target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
removeLibs: []string{
cls[0].GetPublicId(), cls[1].GetPublicId(),
},
@@ -2101,13 +2102,13 @@ func TestAddTargetSources(t *testing.T) {
},
{
name: "Add source on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for sources", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
addSources: []string{cls[1].GetPublicId()},
resultSourceIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
},
{
name: "Add duplicated sources on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for sources", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
addSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
resultSourceIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
},
@@ -2237,19 +2238,19 @@ func TestSetTargetCredentialSources(t *testing.T) {
},
{
name: "Set on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setCredentialSources: []string{cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
},
{
name: "Set duplicate sources on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setCredentialSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
},
{
name: "Set empty on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setCredentialSources: []string{},
resultCredentialSourceIds: nil,
},
@@ -2363,13 +2364,13 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
},
{
name: "Remove 1 of 2 sources",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
removeCredentialSources: []string{cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[0].GetPublicId()},
},
{
name: "Remove 1 duplicate set of 2 sources",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
removeCredentialSources: []string{
cls[1].GetPublicId(), cls[1].GetPublicId(),
},
@@ -2377,7 +2378,7 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
},
{
name: "Remove all sources from target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
removeCredentialSources: []string{
cls[0].GetPublicId(), cls[1].GetPublicId(),
},
+13 -8
View File
@@ -1649,21 +1649,26 @@ func testSessionCredentialParams(t *testing.T, conn *db.DB, wrapper wrapping.Wra
rw := db.New(conn)
ctx := context.Background()
stores := vault.TestCredentialStores(t, conn, wrapper, params.ScopeId, 1)
libs := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2)
kms := kms.TestKms(t, conn, wrapper)
targetRepo, err := target.NewRepository(rw, rw, kms)
require.NoError(err)
tcpTarget, _, _, err := targetRepo.LookupTarget(ctx, params.TargetId)
tar, _, _, err := targetRepo.LookupTarget(ctx, params.TargetId)
require.NoError(err)
require.NotNil(tcpTarget)
_, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tcpTarget.GetPublicId(), tcpTarget.GetVersion(), []string{libs[0].PublicId, libs[1].PublicId})
require.NotNil(tar)
stores := vault.TestCredentialStores(t, conn, wrapper, params.ScopeId, 1)
libIds := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2)
libs := []*target.CredentialLibrary{
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.ApplicationPurpose),
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), credential.ApplicationPurpose),
}
_, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tar.GetPublicId(), tar.GetVersion(), libs)
require.NoError(err)
creds := []*DynamicCredential{
NewDynamicCredential(libs[0].GetPublicId(), credential.ApplicationPurpose),
NewDynamicCredential(libs[0].GetPublicId(), credential.IngressPurpose),
NewDynamicCredential(libs[1].GetPublicId(), credential.EgressPurpose),
NewDynamicCredential(libIds[0].GetPublicId(), credential.ApplicationPurpose),
NewDynamicCredential(libIds[1].GetPublicId(), credential.ApplicationPurpose),
}
params.DynamicCredentials = creds
return params
+2 -2
View File
@@ -21,7 +21,7 @@ type CredentialLibrary struct {
// NewCredentialLibrary creates a new in memory CredentialLibrary
// representing the relationship between targetId and credentialLibraryId.
func NewCredentialLibrary(targetId, credentialLibraryId string, _ ...Option) (*CredentialLibrary, error) {
func NewCredentialLibrary(targetId, credentialLibraryId string, purpose credential.Purpose) (*CredentialLibrary, error) {
const op = "target.NewCredentialLibrary"
if targetId == "" {
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "no target id")
@@ -34,7 +34,7 @@ func NewCredentialLibrary(targetId, credentialLibraryId string, _ ...Option) (*C
CredentialLibrary: &store.CredentialLibrary{
TargetId: targetId,
CredentialLibraryId: credentialLibraryId,
CredentialPurpose: string(credential.ApplicationPurpose), // application is the only purpose currently supported
CredentialPurpose: string(purpose),
},
}
return t, nil
+1 -1
View File
@@ -55,7 +55,7 @@ func TestCredentialLibrary_New(t *testing.T) {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
got, err := target.NewCredentialLibrary(tt.args.targetId, tt.args.libraryId)
got, err := target.NewCredentialLibrary(tt.args.targetId, tt.args.libraryId, credential.ApplicationPurpose)
if tt.wantErr != 0 {
assert.Truef(errors.Match(errors.T(tt.wantErr), err), "want err: %q got: %q", tt.wantErr, err)
assert.Nil(got)
+5 -5
View File
@@ -30,7 +30,7 @@ type options struct {
WithUserId string
WithType subtypes.Subtype
WithHostSources []string
WithCredentialSources []string
WithCredentialLibraries []*CredentialLibrary
WithSessionMaxSeconds uint32
WithSessionConnectionLimit int32
WithPublicId string
@@ -49,7 +49,7 @@ func getDefaultOptions() options {
WithUserId: "",
WithType: "",
WithHostSources: nil,
WithCredentialSources: nil,
WithCredentialLibraries: nil,
WithSessionMaxSeconds: uint32((8 * time.Hour).Seconds()),
WithSessionConnectionLimit: 1,
WithPublicId: "",
@@ -129,10 +129,10 @@ func WithHostSources(hs []string) Option {
}
}
// WithCredentialSources provides an option for providing a list of credential source ids
func WithCredentialSources(cl []string) Option {
// WithCredentialLibraries provides an option for providing a list of credential libraries.
func WithCredentialLibraries(cl []*CredentialLibrary) Option {
return func(o *options) {
o.WithCredentialSources = cl
o.WithCredentialLibraries = cl
}
}
+31 -3
View File
@@ -3,6 +3,8 @@ package target
import (
"testing"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/target/store"
"github.com/hashicorp/boundary/internal/types/subtypes"
"github.com/stretchr/testify/assert"
)
@@ -106,11 +108,37 @@ func Test_GetOpts(t *testing.T) {
testOpts.WithWorkerFilter = `"/foo" == "bar"`
assert.Equal(opts, testOpts)
})
t.Run("WithCredentialSources", func(t *testing.T) {
t.Run("WithCredentialLibraries", func(t *testing.T) {
assert := assert.New(t)
opts := GetOpts(WithCredentialSources([]string{"alice", "bob"}))
opts := GetOpts(WithCredentialLibraries([]*CredentialLibrary{
{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: "alice",
CredentialPurpose: string(credential.ApplicationPurpose),
},
},
{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: "bob",
CredentialPurpose: string(credential.EgressPurpose),
},
},
}))
testOpts := getDefaultOptions()
testOpts.WithCredentialSources = []string{"alice", "bob"}
testOpts.WithCredentialLibraries = []*CredentialLibrary{
{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: "alice",
CredentialPurpose: string(credential.ApplicationPurpose),
},
},
{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: "bob",
CredentialPurpose: string(credential.EgressPurpose),
},
},
}
assert.Equal(opts, testOpts)
})
}
+2 -1
View File
@@ -13,7 +13,8 @@ current_libraries (library_id) as (
-- returns the current list
select credential_library_id
from target_credential_library
where target_id = @target_id
where target_id = @target_id
and credential_purpose = @purpose
),
keep_libraries (library_id) as (
-- returns the KEEP list
+21 -7
View File
@@ -15,10 +15,15 @@ type AllocFunc func() Target
// be used by the Repository.
type VetFunc func(context.Context, Target) error
// VetCredentialLibrariesFunc is a function that checks the given CredentialLibraries
// to ensure that they are valid for a Target subtype.
type VetCredentialLibrariesFunc func(context.Context, []*CredentialLibrary) error
type registryEntry struct {
alloc AllocFunc
vet VetFunc
prefix string
alloc AllocFunc
vet VetFunc
vetCredentialLibraries VetCredentialLibrariesFunc
prefix string
}
type registry struct {
@@ -71,6 +76,14 @@ func (r *registry) vetFunc(s subtypes.Subtype) (VetFunc, bool) {
return entry.vet, ok
}
func (r *registry) vetCredentialLibrariesFunc(s subtypes.Subtype) (VetCredentialLibrariesFunc, bool) {
entry, ok := r.get(s)
if !ok {
return nil, ok
}
return entry.vetCredentialLibraries, ok
}
func (r *registry) idPrefix(s subtypes.Subtype) (string, bool) {
entry, ok := r.get(s)
if !ok {
@@ -103,10 +116,11 @@ func SubtypeFromId(id string) subtypes.Subtype {
// Register registers repository hooks and the prefixes for a provided Subtype. Register
// panics if the subtype has already been registered or if any of the
// prefixes are associated with another subtype.
func Register(s subtypes.Subtype, af AllocFunc, vf VetFunc, prefix string) {
func Register(s subtypes.Subtype, af AllocFunc, vf VetFunc, vclf VetCredentialLibrariesFunc, prefix string) {
subtypeRegistry.set(s, &registryEntry{
alloc: af,
vet: vf,
prefix: prefix,
alloc: af,
vet: vf,
vetCredentialLibraries: vclf,
prefix: prefix,
})
}
+96 -40
View File
@@ -6,17 +6,46 @@ import (
"fmt"
"strings"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/hashicorp/boundary/internal/target/store"
)
// credentialLibrariesPurposeMap is used to group CredentialLibraries by purpose.
type credentialLibrariesPurposeMap map[string][]*CredentialLibrary
func (c credentialLibrariesPurposeMap) add(cl *CredentialLibrary) {
var s []*CredentialLibrary
var ok bool
s, ok = c[cl.CredentialPurpose]
if !ok {
s = make([]*CredentialLibrary, 0, 1)
}
s = append(s, cl)
c[cl.CredentialPurpose] = s
}
func newCredentialLibrariesPurposeMap(cls []*CredentialLibrary) credentialLibrariesPurposeMap {
clpm := make(credentialLibrariesPurposeMap)
for _, p := range credential.ValidPurposes {
clpm[p.String()] = make([]*CredentialLibrary, 0)
}
for _, cl := range cls {
clpm.add(cl)
}
return clpm
}
// AddTargetCredentialSources adds the cIds to the targetId in the repository. The target
// and the list of credential sources attached to the target, after cIds are added,
// will be returned on success.
// The targetVersion must match the current version of the targetId in the repository.
func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, cIds []string, _ ...Option) (Target, []HostSource, []CredentialSource, error) {
func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, cls []*CredentialLibrary, _ ...Option) (Target, []HostSource, []CredentialSource, error) {
const op = "target.(Repository).AddTargetCredentialSources"
if targetId == "" {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing target id")
@@ -24,16 +53,12 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st
if targetVersion == 0 {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing version")
}
if len(cIds) == 0 {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing credential source ids")
if len(cls) == 0 {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing credential libraries")
}
addCredLibs := make([]interface{}, 0, len(cIds))
for _, id := range cIds {
cl, err := NewCredentialLibrary(targetId, id)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory credential library"))
}
addCredLibs := make([]interface{}, 0, len(cls))
for _, cl := range cls {
addCredLibs = append(addCredLibs, cl)
}
@@ -49,6 +74,14 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type))
}
vetCredentialLibraries, ok := subtypeRegistry.vetCredentialLibrariesFunc(t.Subtype())
if !ok {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type))
}
if err := vetCredentialLibraries(ctx, cls); err != nil {
return nil, nil, nil, err
}
target := alloc()
target.SetPublicId(ctx, t.PublicId)
target.SetVersion(targetVersion + 1)
@@ -115,7 +148,7 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st
// DeleteTargetCredentialSources deletes credential sources from a target in the repository.
// The target's current db version must match the targetVersion or an error will be returned.
func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, csIds []string, _ ...Option) (int, error) {
func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, cls []*CredentialLibrary, _ ...Option) (int, error) {
const op = "target.(Repository).DeleteTargetCredentialSources"
if targetId == "" {
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target id")
@@ -123,16 +156,12 @@ func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId
if targetVersion == 0 {
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing version")
}
if len(csIds) == 0 {
if len(cls) == 0 {
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing credential source ids")
}
deleteCredLibs := make([]interface{}, 0, len(csIds))
for _, id := range csIds {
cl, err := NewCredentialLibrary(targetId, id)
if err != nil {
return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory credential library"))
}
deleteCredLibs := make([]interface{}, 0, len(cls))
for _, cl := range cls {
deleteCredLibs = append(deleteCredLibs, cl)
}
@@ -208,7 +237,7 @@ func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId
// SetTargetCredentialSources will set the target's credential sources. Set will add
// and/or delete credential sources as need to reconcile the existing credential sources
// with the request. If clIds is empty, all the credential sources will be cleared from the target.
func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, csIds []string, _ ...Option) ([]HostSource, []CredentialSource, int, error) {
func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, cls []*CredentialLibrary, _ ...Option) ([]HostSource, []CredentialSource, int, error) {
const op = "target.(Repository).SetTargetCredentialSources"
if targetId == "" {
return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target id")
@@ -217,10 +246,18 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing version")
}
changes, err := r.changes(ctx, targetId, csIds)
if err != nil {
return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op)
clpm := newCredentialLibrariesPurposeMap(cls)
var changes []*change
for purpose, cls := range clpm {
c, err := r.changes(ctx, targetId, cls, purpose)
if err != nil {
return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op)
}
changes = append(changes, c...)
}
if len(changes) == 0 {
// Nothing needs to be changed, return early
hostSets, err := fetchHostSources(ctx, r.reader, targetId)
@@ -236,15 +273,11 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
var deleteCredLibs, addCredLibs []interface{}
for _, c := range changes {
cl, err := NewCredentialLibrary(targetId, c.LibraryId)
if err != nil {
return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory target credential library"))
}
switch c.Action {
switch c.action {
case "delete":
deleteCredLibs = append(deleteCredLibs, cl)
deleteCredLibs = append(deleteCredLibs, c.credentialLibrary)
case "add":
addCredLibs = append(addCredLibs, cl)
addCredLibs = append(addCredLibs, c.credentialLibrary)
}
}
@@ -259,6 +292,15 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
if !ok {
return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type))
}
vetCredentialLibraries, ok := subtypeRegistry.vetCredentialLibrariesFunc(t.Subtype())
if !ok {
return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type))
}
if err := vetCredentialLibraries(ctx, cls); err != nil {
return nil, nil, db.NoRowsAffected, err
}
target := alloc()
target.SetPublicId(ctx, t.PublicId)
target.SetVersion(targetVersion + 1)
@@ -343,28 +385,33 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
}
type change struct {
action string
credentialLibrary *CredentialLibrary
}
type changeQueryResult struct {
Action string
LibraryId string
}
func (r *Repository) changes(ctx context.Context, targetId string, clIds []string) ([]*change, error) {
func (r *Repository) changes(ctx context.Context, targetId string, cls []*CredentialLibrary, purpose string) ([]*change, error) {
const op = "target.(Repository).changes"
// TODO ensure that all cls have the same purpose as the given purpose?
var inClauseSpots []string
// starts at 2 because there is already a @1 in the query
for i := 2; i < len(clIds)+2; i++ {
inClauseSpots = append(inClauseSpots, fmt.Sprintf("@%d", i))
var params []interface{}
params = append(params, sql.Named("target_id", targetId), sql.Named("purpose", purpose))
for idx, cl := range cls {
params = append(params, sql.Named(fmt.Sprintf("%d", idx+1), cl.CredentialLibraryId))
inClauseSpots = append(inClauseSpots, fmt.Sprintf("@%d", idx+1))
}
inClause := strings.Join(inClauseSpots, ",")
if inClause == "" {
inClause = "''"
}
query := fmt.Sprintf(setChangesQuery, inClause)
var params []interface{}
params = append(params, sql.Named("target_id", targetId))
for idx, id := range clIds {
params = append(params, sql.Named(fmt.Sprintf("%d", idx+2), id))
}
query := fmt.Sprintf(setChangesQuery, inClause)
rows, err := r.reader.Query(ctx, query, params)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("query failed"))
@@ -373,11 +420,20 @@ func (r *Repository) changes(ctx context.Context, targetId string, clIds []strin
var changes []*change
for rows.Next() {
var chg change
var chg changeQueryResult
if err := r.reader.ScanRows(rows, &chg); err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("scan row failed"))
}
changes = append(changes, &chg)
changes = append(changes, &change{
action: chg.Action,
credentialLibrary: &CredentialLibrary{
CredentialLibrary: &store.CredentialLibrary{
TargetId: targetId,
CredentialLibraryId: chg.LibraryId,
CredentialPurpose: purpose,
},
},
})
}
return changes, nil
}
@@ -0,0 +1,258 @@
package target_test
import (
"context"
"testing"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/credential/vault"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/targettest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRepository_SetTargetCredentialSources(t *testing.T) {
target.Register(targettest.Subtype, targettest.Alloc, targettest.Vet, targettest.VetCredentialLibraries, targettest.TargetPrefix)
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
testKms := kms.TestKms(t, conn, wrapper)
repo, err := target.NewRepository(rw, rw, testKms)
require.NoError(t, err)
iamRepo := iam.TestRepo(t, conn, wrapper)
_, proj := iam.TestScopes(t, iamRepo)
cs := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 2)
lib1 := credLibs[0]
lib2 := credLibs[1]
setupFn := func(tar target.Target) ([]target.CredentialSource, []*target.CredentialLibrary) {
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 10)
cls := make([]*target.CredentialLibrary, 0, len(credLibs))
for _, cl := range credLibs {
cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), cl.PublicId, credential.ApplicationPurpose))
}
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls)
require.NoError(t, err)
require.Equal(t, 10, len(created))
return created, cls
}
type args struct {
targetVersion uint32
cls []*target.CredentialLibrary
addToOrigLibs bool
}
tests := []struct {
name string
setup func(target.Target) ([]target.CredentialSource, []*target.CredentialLibrary)
args args
wantAffectedRows int
wantErr bool
wantErrCode errors.Code
}{
{
name: "clear",
setup: setupFn,
args: args{
targetVersion: 2,
cls: []*target.CredentialLibrary{},
},
wantErr: false,
wantAffectedRows: 10,
},
{
name: "no-change",
setup: setupFn,
args: args{
targetVersion: 2,
cls: []*target.CredentialLibrary{},
addToOrigLibs: true,
},
wantErr: false,
wantAffectedRows: 0,
},
{
name: "add-cred-sources",
setup: setupFn,
args: args{
targetVersion: 2,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: true,
},
wantErr: false,
wantAffectedRows: 2,
},
{
name: "add-multiple-purposes",
setup: setupFn,
args: args{
targetVersion: 2,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: true,
},
wantErr: false,
wantAffectedRows: 3,
},
{
name: "remove-add-change-purpose",
setup: func(tar target.Target) ([]target.CredentialSource, []*target.CredentialLibrary) {
cls := []*target.CredentialLibrary{
target.TestNewCredentialLibrary(tar.GetPublicId(), lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary(tar.GetPublicId(), lib2.PublicId, credential.ApplicationPurpose),
}
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls)
require.NoError(t, err)
require.Equal(t, 2, len(created))
return created, cls
},
args: args{
targetVersion: 2,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.EgressPurpose),
},
addToOrigLibs: false,
},
wantErr: false,
wantAffectedRows: 4,
},
{
name: "zero version",
setup: setupFn,
args: args{
targetVersion: 0,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: true,
},
wantErr: true,
wantErrCode: errors.InvalidParameter,
},
{
name: "bad version",
setup: setupFn,
args: args{
targetVersion: 1000,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: true,
},
wantErr: true,
wantErrCode: errors.VersionMismatch,
},
{
name: "remove existing and add cred libs",
setup: setupFn,
args: args{
targetVersion: 2,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: false,
},
wantErr: false,
wantAffectedRows: 12,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tar := targettest.TestNewTestTarget(t, conn, proj.PublicId, tt.name)
var origCredSources []target.CredentialSource
var origCredLibraries []*target.CredentialLibrary
if tt.setup != nil {
origCredSources, origCredLibraries = tt.setup(tar)
}
wantCredSources := make(map[string]target.CredentialSource)
for _, cl := range tt.args.cls {
cl.TargetId = tar.GetPublicId()
wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = &target.TargetLibrary{
CredentialLibrary: cl.CredentialLibrary,
}
}
if tt.args.addToOrigLibs {
tt.args.cls = append(tt.args.cls, origCredLibraries...)
for _, cl := range origCredLibraries {
wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = &target.TargetLibrary{
CredentialLibrary: cl.CredentialLibrary,
}
}
}
origTarget, _, lookupCredSources, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
require.NoError(err)
assert.Equal(origCredSources, lookupCredSources)
_, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), tar.GetPublicId(), tt.args.targetVersion, tt.args.cls)
if tt.wantErr {
require.Error(err)
assert.Equal(0, affectedRows)
assert.Truef(errors.Match(errors.T(tt.wantErrCode), err), "unexpected error %s", err.Error())
return
}
t.Log(err)
require.NoError(err)
assert.Equal(tt.wantAffectedRows, affectedRows)
assert.Equal(len(wantCredSources), len(got))
for _, cs := range got {
w, ok := wantCredSources[cs.Id()+"_"+string(cs.CredentialPurpose())]
assert.True(ok, "got unexpected credentialsource %v", cs)
assert.Equal(w.Id(), cs.Id())
assert.Equal(w.CredentialPurpose(), cs.CredentialPurpose())
}
foundTarget, _, _, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
require.NoError(err)
if tt.name != "no-change" {
assert.Equalf(tt.args.targetVersion+1, foundTarget.GetVersion(), "%s unexpected version: %d/%d", tt.name, tt.args.targetVersion+1, foundTarget.GetVersion())
assert.Equalf(origTarget.GetVersion(), foundTarget.GetVersion()-1, "%s unexpected version: %d/%d", tt.name, origTarget.GetVersion(), foundTarget.GetVersion()-1)
}
})
}
t.Run("missing-target-id", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
cl1 := target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose)
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "", 1, []*target.CredentialLibrary{cl1})
require.Error(err)
assert.Truef(errors.Match(errors.T(errors.InvalidParameter), err), "unexpected error %s", err.Error())
})
t.Run("target-not-found", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
cl1 := target.TestNewCredentialLibrary("fake-target-id", lib1.PublicId, credential.ApplicationPurpose)
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "fake-target-id", 1, []*target.CredentialLibrary{cl1})
require.Error(err)
assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error())
})
}
@@ -0,0 +1,307 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.17.3
// source: controller/storage/target/targettest/store/v1/target.proto
package store
import (
timestamp "github.com/hashicorp/boundary/internal/db/timestamp"
_ "github.com/hashicorp/boundary/sdk/pbs/controller/protooptions"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Target struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// public_id is used to access the targettest.Target via an API
// @inject_tag: gorm:"primary_key"
PublicId string `protobuf:"bytes,10,opt,name=public_id,json=publicId,proto3" json:"public_id,omitempty" gorm:"primary_key"`
// scope id for the targettest.Target
// @inject_tag: `gorm:"default:null"`
ScopeId string `protobuf:"bytes,20,opt,name=scope_id,json=scopeId,proto3" json:"scope_id,omitempty" gorm:"default:null"`
// name is the optional friendly name used to
// access the targettest.Target via an API
// @inject_tag: `gorm:"default:null"`
Name string `protobuf:"bytes,30,opt,name=name,proto3" json:"name,omitempty" gorm:"default:null"`
// description of the targettest.Target
// @inject_tag: `gorm:"default:null"`
Description string `protobuf:"bytes,40,opt,name=description,proto3" json:"description,omitempty" gorm:"default:null"`
// create_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
CreateTime *timestamp.Timestamp `protobuf:"bytes,50,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty" gorm:"default:current_timestamp"`
// update_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
UpdateTime *timestamp.Timestamp `protobuf:"bytes,60,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty" gorm:"default:current_timestamp"`
// version allows optimistic locking of the targettest.Target when modifying the
// targettest.Target
// @inject_tag: `gorm:"default:null"`
Version uint32 `protobuf:"varint,70,opt,name=version,proto3" json:"version,omitempty" gorm:"default:null"`
// default port of the targettest.Target
// @inject_tag: `gorm:"default:null"`
DefaultPort uint32 `protobuf:"varint,80,opt,name=default_port,json=defaultPort,proto3" json:"default_port,omitempty" gorm:"default:null"`
// Maximum total lifetime of a created session, in seconds
// @inject_tag: `gorm:"default:null"`
SessionMaxSeconds uint32 `protobuf:"varint,100,opt,name=session_max_seconds,json=sessionMaxSeconds,proto3" json:"session_max_seconds,omitempty" gorm:"default:null"`
// Maximum number of connections in a session
// @inject_tag: `gorm:"default:null"`
SessionConnectionLimit int32 `protobuf:"varint,110,opt,name=session_connection_limit,json=sessionConnectionLimit,proto3" json:"session_connection_limit,omitempty" gorm:"default:null"`
// A boolean expression that allows filtering the workers that can handle a session
// @inject_tag: `gorm:"default:null"`
WorkerFilter string `protobuf:"bytes,120,opt,name=worker_filter,json=workerFilter,proto3" json:"worker_filter,omitempty" gorm:"default:null"`
}
func (x *Target) Reset() {
*x = Target{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_storage_target_targettest_store_v1_target_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Target) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Target) ProtoMessage() {}
func (x *Target) ProtoReflect() protoreflect.Message {
mi := &file_controller_storage_target_targettest_store_v1_target_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Target.ProtoReflect.Descriptor instead.
func (*Target) Descriptor() ([]byte, []int) {
return file_controller_storage_target_targettest_store_v1_target_proto_rawDescGZIP(), []int{0}
}
func (x *Target) GetPublicId() string {
if x != nil {
return x.PublicId
}
return ""
}
func (x *Target) GetScopeId() string {
if x != nil {
return x.ScopeId
}
return ""
}
func (x *Target) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Target) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
func (x *Target) GetCreateTime() *timestamp.Timestamp {
if x != nil {
return x.CreateTime
}
return nil
}
func (x *Target) GetUpdateTime() *timestamp.Timestamp {
if x != nil {
return x.UpdateTime
}
return nil
}
func (x *Target) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *Target) GetDefaultPort() uint32 {
if x != nil {
return x.DefaultPort
}
return 0
}
func (x *Target) GetSessionMaxSeconds() uint32 {
if x != nil {
return x.SessionMaxSeconds
}
return 0
}
func (x *Target) GetSessionConnectionLimit() int32 {
if x != nil {
return x.SessionConnectionLimit
}
return 0
}
func (x *Target) GetWorkerFilter() string {
if x != nil {
return x.WorkerFilter
}
return ""
}
var File_controller_storage_target_targettest_store_v1_target_proto protoreflect.FileDescriptor
var file_controller_storage_target_targettest_store_v1_target_proto_rawDesc = []byte{
0x0a, 0x3a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x6f,
0x72, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x74, 0x61, 0x72, 0x67,
0x65, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f,
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2d, 0x63, 0x6f,
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x74, 0x65,
0x73, 0x74, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x2f, 0x63, 0x6f, 0x6e,
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f,
0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x63, 0x6f,
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f,
0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc3, 0x05, 0x0a, 0x06, 0x54, 0x61, 0x72,
0x67, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64,
0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64,
0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01,
0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x04, 0x6e,
0x61, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, 0x10, 0xc2, 0xdd, 0x29, 0x0c, 0x0a,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x12, 0x40, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, 0x64, 0x65,
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69,
0x6d, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65,
0x12, 0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a,
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75,
0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x2a, 0xc2,
0xdd, 0x29, 0x26, 0x0a, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74,
0x12, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66,
0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75,
0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x5c, 0x0a, 0x13, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x64, 0x20,
0x01, 0x28, 0x0d, 0x42, 0x2c, 0xc2, 0xdd, 0x29, 0x28, 0x0a, 0x11, 0x53, 0x65, 0x73, 0x73, 0x69,
0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x13, 0x73, 0x65,
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64,
0x73, 0x52, 0x11, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63,
0x6f, 0x6e, 0x64, 0x73, 0x12, 0x70, 0x0a, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74,
0x18, 0x6e, 0x20, 0x01, 0x28, 0x05, 0x42, 0x36, 0xc2, 0xdd, 0x29, 0x32, 0x0a, 0x16, 0x53, 0x65,
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c,
0x69, 0x6d, 0x69, 0x74, 0x12, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f,
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x16,
0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x46, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72,
0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x78, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xc2,
0xdd, 0x29, 0x1d, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65,
0x72, 0x12, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x46,
0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73,
0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f,
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65,
0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_controller_storage_target_targettest_store_v1_target_proto_rawDescOnce sync.Once
file_controller_storage_target_targettest_store_v1_target_proto_rawDescData = file_controller_storage_target_targettest_store_v1_target_proto_rawDesc
)
func file_controller_storage_target_targettest_store_v1_target_proto_rawDescGZIP() []byte {
file_controller_storage_target_targettest_store_v1_target_proto_rawDescOnce.Do(func() {
file_controller_storage_target_targettest_store_v1_target_proto_rawDescData = protoimpl.X.CompressGZIP(file_controller_storage_target_targettest_store_v1_target_proto_rawDescData)
})
return file_controller_storage_target_targettest_store_v1_target_proto_rawDescData
}
var file_controller_storage_target_targettest_store_v1_target_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_controller_storage_target_targettest_store_v1_target_proto_goTypes = []interface{}{
(*Target)(nil), // 0: controller.storage.target.targettest.store.v1.Target
(*timestamp.Timestamp)(nil), // 1: controller.storage.timestamp.v1.Timestamp
}
var file_controller_storage_target_targettest_store_v1_target_proto_depIdxs = []int32{
1, // 0: controller.storage.target.targettest.store.v1.Target.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
1, // 1: controller.storage.target.targettest.store.v1.Target.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_controller_storage_target_targettest_store_v1_target_proto_init() }
func file_controller_storage_target_targettest_store_v1_target_proto_init() {
if File_controller_storage_target_targettest_store_v1_target_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_controller_storage_target_targettest_store_v1_target_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Target); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_controller_storage_target_targettest_store_v1_target_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_controller_storage_target_targettest_store_v1_target_proto_goTypes,
DependencyIndexes: file_controller_storage_target_targettest_store_v1_target_proto_depIdxs,
MessageInfos: file_controller_storage_target_targettest_store_v1_target_proto_msgTypes,
}.Build()
File_controller_storage_target_targettest_store_v1_target_proto = out.File
file_controller_storage_target_targettest_store_v1_target_proto_rawDesc = nil
file_controller_storage_target_targettest_store_v1_target_proto_goTypes = nil
file_controller_storage_target_targettest_store_v1_target_proto_depIdxs = nil
}
+267
View File
@@ -0,0 +1,267 @@
// Package targettest provides a test target subtype for use by the target
// package. Note that it leverages the tcp.Target's database table to avoid
// needing schema migrations just for tests.
package targettest
import (
"context"
"testing"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/timestamp"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/targettest/store"
"github.com/hashicorp/boundary/internal/types/subtypes"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
const (
Subtype = subtypes.Subtype("tcp")
TargetPrefix = "ttcp"
)
// Target is a target.Target used for tests.
type Target struct {
*store.Target
tableName string `gorm:"-"`
}
var (
_ target.Target = (*Target)(nil)
_ db.VetForWriter = (*Target)(nil)
_ oplog.ReplayableMessage = (*Target)(nil)
)
// VetForWrite implements db.VetForWrite() interface and validates the tcp target
// before it's written.
func (t *Target) VetForWrite(ctx context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error {
const op = "target_test.(Target).VetForWrite"
if t.PublicId == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing public id")
}
if opType == db.CreateOp {
if t.ScopeId == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing scope id")
}
if t.Name == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing name")
}
}
return nil
}
// TableName returns the tablename to override the default gorm table name
func (t *Target) TableName() string {
if t.tableName != "" {
return t.tableName
}
return "target_tcp"
}
// SetTableName sets the tablename and satisfies the ReplayableMessage
// interface. If the caller attempts to set the name to "" the name will be
// reset to the default name.
func (t *Target) SetTableName(n string) {
t.tableName = n
}
func (t *Target) GetPublicId() string {
return t.PublicId
}
func (t *Target) GetScopeId() string {
return t.ScopeId
}
func (t *Target) GetDefaultPort() uint32 {
return t.DefaultPort
}
func (t *Target) GetName() string {
return t.Name
}
func (t *Target) GetDescription() string {
return t.Description
}
func (t *Target) GetVersion() uint32 {
return t.Version
}
func (t *Target) GetType() subtypes.Subtype {
return Subtype
}
func (t *Target) GetCreateTime() *timestamp.Timestamp {
return t.CreateTime
}
func (t *Target) GetUpdateTime() *timestamp.Timestamp {
return t.UpdateTime
}
func (t *Target) GetSessionMaxSeconds() uint32 {
return t.SessionMaxSeconds
}
func (t *Target) GetSessionConnectionLimit() int32 {
return t.SessionConnectionLimit
}
func (t *Target) GetWorkerFilter() string {
return t.WorkerFilter
}
func (t *Target) Clone() target.Target {
cp := proto.Clone(t.Target)
return &Target{
Target: cp.(*store.Target),
}
}
func (t *Target) SetPublicId(_ context.Context, publicId string) error {
t.PublicId = publicId
return nil
}
func (t *Target) SetScopeId(scopeId string) {
t.ScopeId = scopeId
}
func (t *Target) SetName(name string) {
t.Name = name
}
func (t *Target) SetDescription(description string) {
t.Description = description
}
func (t *Target) SetVersion(v uint32) {
t.Version = v
}
func (t *Target) SetDefaultPort(port uint32) {
t.DefaultPort = port
}
func (t *Target) SetCreateTime(ts *timestamp.Timestamp) {
t.CreateTime = ts
}
func (t *Target) SetUpdateTime(ts *timestamp.Timestamp) {
t.UpdateTime = ts
}
func (t *Target) SetSessionMaxSeconds(s uint32) {
t.SessionMaxSeconds = s
}
func (t *Target) SetSessionConnectionLimit(l int32) {
t.SessionConnectionLimit = l
}
func (t *Target) SetWorkerFilter(f string) {
t.WorkerFilter = f
}
func (t *Target) Oplog(op oplog.OpType) oplog.Metadata {
return oplog.Metadata{
"resource-public-id": []string{t.PublicId},
"resource-type": []string{"tcp target"},
"op-type": []string{op.String()},
"scope-id": []string{t.ScopeId},
}
}
// Alloc creates an in-memory Target.
func Alloc() target.Target {
return &Target{
Target: &store.Target{},
}
}
// Vet checks that the given Target is a targettest.Target and that it is not nil.
func Vet(ctx context.Context, t target.Target) error {
const op = "targettest.Vet"
tt, ok := t.(*Target)
if !ok {
return errors.New(ctx, errors.InvalidParameter, op, "target is not a tcp.Target")
}
if tt == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing target")
}
if tt.Target == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing target store")
}
return nil
}
// VetCredentialLibraries allows for any CredentialLibraries.
func VetCredentialLibraries(_ context.Context, _ []*target.CredentialLibrary) error {
return nil
}
// New creates a targettest.Target.
func New(scopeId string, opt ...target.Option) (*Target, error) {
const op = "target_test.New"
opts := target.GetOpts(opt...)
if scopeId == "" {
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing scope id")
}
t := &Target{
Target: &store.Target{
ScopeId: scopeId,
Name: opts.WithName,
Description: opts.WithDescription,
DefaultPort: opts.WithDefaultPort,
SessionConnectionLimit: opts.WithSessionConnectionLimit,
SessionMaxSeconds: opts.WithSessionMaxSeconds,
WorkerFilter: opts.WithWorkerFilter,
},
}
return t, nil
}
// TestNewTestTarget is a test helper for creating a targettest.Target.
func TestNewTestTarget(t *testing.T, conn *db.DB, scopeId, name string, opt ...target.Option) *Target {
t.Helper()
opt = append(opt, target.WithName(name))
opts := target.GetOpts(opt...)
require := require.New(t)
rw := db.New(conn)
tar, err := New(scopeId, opt...)
require.NoError(err)
id, err := db.NewPublicId(TargetPrefix)
require.NoError(err)
tar.PublicId = id
err = rw.Create(context.Background(), tar)
require.NoError(err)
if len(opts.WithHostSources) > 0 {
newHostSets := make([]interface{}, 0, len(opts.WithHostSources))
for _, s := range opts.WithHostSources {
hostSet, err := target.NewTargetHostSet(tar.PublicId, s)
require.NoError(err)
newHostSets = append(newHostSets, hostSet)
}
err := rw.CreateItems(context.Background(), newHostSets)
require.NoError(err)
}
if len(opts.WithCredentialLibraries) > 0 {
newCredLibs := make([]interface{}, 0, len(opts.WithCredentialLibraries))
for _, cl := range opts.WithCredentialLibraries {
cl.TargetId = tar.PublicId
newCredLibs = append(newCredLibs, cl)
}
err := rw.CreateItems(context.Background(), newCredLibs)
require.NoError(err)
}
return tar
}
+16 -1
View File
@@ -2,13 +2,15 @@ package tcp
import (
"context"
"fmt"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/target"
)
func init() {
target.Register(Subtype, allocTarget, vet, TargetPrefix)
target.Register(Subtype, allocTarget, vet, vetCredentialLibraries, TargetPrefix)
}
const (
@@ -35,3 +37,16 @@ func vet(ctx context.Context, t target.Target) error {
}
return nil
}
// vetCredentialLibraries checks that all of the provided credential libriaries have a CredentialPurpose
// of ApplicationPurpose. Any other CredentialPurpose will result in an error.
func vetCredentialLibraries(ctx context.Context, cls []*target.CredentialLibrary) error {
const op = "tcp.vetCredentialLibraries"
for _, cl := range cls {
if cl.CredentialPurpose != string(credential.ApplicationPurpose) {
return errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("tcp.Target only supports credential purpose: %q", credential.ApplicationPurpose))
}
}
return nil
}
@@ -2,10 +2,10 @@ package tcp_test
import (
"context"
"sort"
"testing"
"time"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/credential/vault"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
@@ -13,6 +13,7 @@ import (
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/store"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -39,14 +40,14 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
type args struct {
targetVersion uint32
credLibIds []string
cls []*target.CredentialLibrary
}
tests := []struct {
name string
args args
wantCredLibIds []string
wantErr bool
wantErrCode errors.Code
name string
args args
wantCredSources map[string]target.CredentialSource
wantErr bool
wantErrCode errors.Code
}{
{
name: "zero-version",
@@ -68,34 +69,95 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
name: "valid-single-source",
args: args{
targetVersion: 1,
credLibIds: []string{lib1.PublicId},
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
},
},
wantCredLibIds: []string{lib1.PublicId},
wantErr: false,
wantCredSources: map[string]target.CredentialSource{
lib1.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetLibrary{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: lib1.PublicId,
CredentialPurpose: string(credential.ApplicationPurpose),
},
},
},
wantErr: false,
},
{
name: "valid-multiple-sources",
args: args{
targetVersion: 1,
credLibIds: []string{lib1.PublicId, lib2.PublicId, lib3.PublicId},
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib3.PublicId, credential.ApplicationPurpose),
},
},
wantCredLibIds: []string{lib1.PublicId, lib2.PublicId, lib3.PublicId},
wantErr: false,
wantCredSources: map[string]target.CredentialSource{
lib1.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetLibrary{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: lib1.PublicId,
CredentialPurpose: string(credential.ApplicationPurpose),
},
},
lib2.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetLibrary{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: lib2.PublicId,
CredentialPurpose: string(credential.ApplicationPurpose),
},
},
lib3.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetLibrary{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: lib3.PublicId,
CredentialPurpose: string(credential.ApplicationPurpose),
},
},
},
wantErr: false,
},
{
name: "invalid-source-id",
args: args{
targetVersion: 1,
credLibIds: []string{lib1.PublicId, lib2.PublicId, lib3.PublicId, "invalid-source-id"},
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib3.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", "invalid-source-id", credential.ApplicationPurpose),
},
},
wantErr: true,
wantErrCode: errors.NotSpecificIntegrity,
},
{
name: "egress-credential-purpose",
args: args{
targetVersion: 1,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose),
},
},
wantErr: true,
wantErrCode: errors.InvalidParameter,
},
{
name: "ingress-credential-purpose",
args: args{
targetVersion: 1,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.IngressPurpose),
},
},
wantErr: true,
wantErrCode: errors.InvalidParameter,
},
{
name: "bad-version",
args: args{
targetVersion: 1000,
credLibIds: []string{lib1.PublicId},
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
},
},
wantErr: true,
wantErrCode: errors.VersionMismatch,
@@ -106,20 +168,25 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
assert, require := assert.New(t), require.New(t)
projTarget := tcp.TestTarget(t, conn, staticProj.PublicId, tt.name)
gotTarget, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, tt.args.targetVersion, tt.args.credLibIds)
for _, cl := range tt.args.cls {
cl.TargetId = projTarget.PublicId
}
gotTarget, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, tt.args.targetVersion, tt.args.cls)
if tt.wantErr {
require.Error(err)
assert.Truef(errors.Match(errors.T(tt.wantErrCode), err), "unexpected error %s", err.Error())
return
}
require.NoError(err)
assert.Len(gotCredSources, len(tt.wantCredLibIds))
gotCredSourcesMap := map[string]target.CredentialSource{}
for _, s := range gotCredSources {
gotCredSourcesMap[s.Id()] = s
}
for _, id := range tt.wantCredLibIds {
assert.NotEmpty(gotCredSourcesMap[id])
assert.Len(gotCredSources, len(tt.wantCredSources))
for _, cs := range gotCredSources {
w, ok := tt.wantCredSources[cs.Id()+"_"+string(cs.CredentialPurpose())]
assert.True(ok, "got unexpected credentialsource %v", cs)
assert.Equal(w.Id(), cs.Id())
assert.Equal(w.CredentialPurpose(), cs.CredentialPurpose())
}
// test to see of the target version update oplog was created
@@ -132,9 +199,13 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
assert.Equal(projTarget.GetVersion(), tar.GetVersion()-1)
assert.True(proto.Equal(gotTarget.(*tcp.Target), tar.(*tcp.Target)))
assert.Equal(gotCredSources, lookupCredSources)
for _, s := range lookupCredSources {
assert.NotEmpty(gotCredSourcesMap[s.Id()])
assert.Equal(projTarget.PublicId, s.TargetId())
for _, cs := range lookupCredSources {
w, ok := tt.wantCredSources[cs.Id()+"_"+string(cs.CredentialPurpose())]
assert.True(ok, "got unexpected credentialsource %v", cs)
assert.Equal(w.Id(), cs.Id())
assert.Equal(w.CredentialPurpose(), cs.CredentialPurpose())
assert.Equal(projTarget.PublicId, cs.TargetId())
}
})
}
@@ -142,18 +213,22 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
assert, require := assert.New(t), require.New(t)
projTarget := tcp.TestTarget(t, conn, staticProj.PublicId, "add-existing")
_, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []string{lib1.PublicId})
cl1 := target.TestNewCredentialLibrary(projTarget.PublicId, lib1.PublicId, credential.ApplicationPurpose)
cl2 := target.TestNewCredentialLibrary(projTarget.PublicId, lib2.PublicId, credential.ApplicationPurpose)
cl3 := target.TestNewCredentialLibrary(projTarget.PublicId, lib3.PublicId, credential.ApplicationPurpose)
_, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []*target.CredentialLibrary{cl1})
require.NoError(err)
assert.Len(gotCredSources, 1)
assert.Equal(lib1.PublicId, gotCredSources[0].Id())
// Adding lib1 again should error
_, _, _, err = repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []string{lib1.PublicId})
_, _, _, err = repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []*target.CredentialLibrary{cl1})
require.Error(err)
assert.True(errors.Match(errors.T(errors.NotUnique), err))
// Adding multiple with lib1 in set should error
_, _, _, err = repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []string{lib3.PublicId, lib2.PublicId, lib1.PublicId})
_, _, _, err = repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []*target.CredentialLibrary{cl3, cl2, cl1})
require.Error(err)
assert.True(errors.Match(errors.T(errors.NotUnique), err))
@@ -166,7 +241,8 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
t.Run("target-not-found", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
_, _, _, err := repo.AddTargetCredentialSources(context.Background(), "fake-target-id", 1, []string{lib1.PublicId})
cl1 := target.TestNewCredentialLibrary("fake-target-id", lib1.PublicId, credential.ApplicationPurpose)
_, _, _, err := repo.AddTargetCredentialSources(context.Background(), "fake-target-id", 1, []*target.CredentialLibrary{cl1})
require.Error(err)
assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error())
@@ -275,29 +351,29 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
assert, require := assert.New(t), require.New(t)
cs := css[i]
target := tcp.TestTarget(t, conn, proj.PublicId, tt.name)
tar := tcp.TestTarget(t, conn, proj.PublicId, tt.name)
clIds := make([]string, 0, tt.args.createCnt)
cls := make([]*target.CredentialLibrary, 0, tt.args.createCnt)
if tt.args.createCnt > 0 {
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.PublicId, tt.args.createCnt)
for _, cl := range credLibs {
clIds = append(clIds, cl.PublicId)
cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), cl.PublicId, credential.ApplicationPurpose))
}
}
_, _, addedCredSources, err := repo.AddTargetCredentialSources(context.Background(), target.GetPublicId(), 1, clIds)
_, _, addedCredSources, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls)
require.NoError(err)
assert.Equal(tt.args.createCnt, len(addedCredSources))
deleteCredSources := make([]string, 0, tt.args.deleteCnt)
deleteCredSources := make([]*target.CredentialLibrary, 0, tt.args.deleteCnt)
for i := 0; i < tt.args.deleteCnt; i++ {
deleteCredSources = append(deleteCredSources, clIds[i])
deleteCredSources = append(deleteCredSources, cls[i])
}
var targetId string
switch {
case tt.args.targetIdOverride != nil:
targetId = *tt.args.targetIdOverride
default:
targetId = target.GetPublicId()
targetId = tar.GetPublicId()
}
var targetVersion uint32
switch {
@@ -317,7 +393,7 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
assert.Equal(tt.wantRowsDeleted, deletedRows)
// we should find the oplog for the delete of target credential libraries
err = db.TestVerifyOplog(t, rw, target.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
err = db.TestVerifyOplog(t, rw, tar.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
assert.NoError(err)
})
}
@@ -333,18 +409,22 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
lib3 := libs[2]
projTarget := tcp.TestTarget(t, conn, proj.PublicId, "add-existing")
_, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []string{lib1.PublicId, lib2.PublicId})
cl1 := target.TestNewCredentialLibrary(projTarget.PublicId, lib1.PublicId, credential.ApplicationPurpose)
cl2 := target.TestNewCredentialLibrary(projTarget.PublicId, lib2.PublicId, credential.ApplicationPurpose)
cl3 := target.TestNewCredentialLibrary(projTarget.PublicId, lib3.PublicId, credential.ApplicationPurpose)
_, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []*target.CredentialLibrary{cl1, cl2})
require.NoError(err)
assert.Len(gotCredSources, 2)
// Deleting an unassociated source should return an error
delCount, err := repo.DeleteTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []string{lib3.PublicId})
delCount, err := repo.DeleteTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []*target.CredentialLibrary{cl3})
require.Error(err)
assert.True(errors.Match(errors.T(errors.MultipleRecords), err))
assert.Equal(0, delCount)
// Deleting sources which includes an unassociated source should return an error
delCount, err = repo.DeleteTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []string{lib1.PublicId, lib2.PublicId, lib3.PublicId})
delCount, err = repo.DeleteTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []*target.CredentialLibrary{cl1, cl2, cl3})
require.Error(err)
assert.True(errors.Match(errors.T(errors.MultipleRecords), err))
assert.Equal(0, delCount)
@@ -373,26 +453,26 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
lib1 := credLibs[0]
lib2 := credLibs[1]
setupFn := func(target target.Target) []target.CredentialSource {
setupFn := func(tar target.Target) ([]target.CredentialSource, []*target.CredentialLibrary) {
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 10)
clIds := make([]string, 0, len(credLibs))
cls := make([]*target.CredentialLibrary, 0, len(credLibs))
for _, cl := range credLibs {
clIds = append(clIds, cl.PublicId)
cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), cl.PublicId, credential.ApplicationPurpose))
}
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), target.GetPublicId(), 1, clIds)
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls)
require.NoError(t, err)
require.Equal(t, 10, len(created))
return created
return created, cls
}
type args struct {
targetVersion uint32
clIds []string
cls []*target.CredentialLibrary
addToOrigLibs bool
}
tests := []struct {
name string
setup func(target.Target) []target.CredentialSource
setup func(target.Target) ([]target.CredentialSource, []*target.CredentialLibrary)
args args
wantAffectedRows int
wantErr bool
@@ -403,7 +483,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
setup: setupFn,
args: args{
targetVersion: 2,
clIds: []string{},
cls: []*target.CredentialLibrary{},
},
wantErr: false,
wantAffectedRows: 10,
@@ -413,7 +493,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
setup: setupFn,
args: args{
targetVersion: 2,
clIds: []string{},
cls: []*target.CredentialLibrary{},
addToOrigLibs: true,
},
wantErr: false,
@@ -424,7 +504,10 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
setup: setupFn,
args: args{
targetVersion: 2,
clIds: []string{lib1.PublicId, lib2.PublicId},
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: true,
},
wantErr: false,
@@ -435,7 +518,10 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
setup: setupFn,
args: args{
targetVersion: 0,
clIds: []string{lib1.PublicId, lib2.PublicId},
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: true,
},
wantErr: true,
@@ -446,7 +532,10 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
setup: setupFn,
args: args{
targetVersion: 1000,
clIds: []string{lib1.PublicId, lib2.PublicId},
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: true,
},
wantErr: true,
@@ -457,12 +546,39 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
setup: setupFn,
args: args{
targetVersion: 2,
clIds: []string{lib1.PublicId, lib2.PublicId},
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: false,
},
wantErr: false,
wantAffectedRows: 12,
},
{
name: "egress-credential-purpose",
setup: setupFn,
args: args{
targetVersion: 1,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose),
},
},
wantErr: true,
wantErrCode: errors.InvalidParameter,
},
{
name: "ingress-credential-purpose",
setup: setupFn,
args: args{
targetVersion: 1,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.IngressPurpose),
},
},
wantErr: true,
wantErrCode: errors.InvalidParameter,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -471,22 +587,32 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
tar := tcp.TestTarget(t, conn, proj.PublicId, tt.name)
var origCredSources []target.CredentialSource
var origCredLibraries []*target.CredentialLibrary
if tt.setup != nil {
origCredSources = tt.setup(tar)
origCredSources, origCredLibraries = tt.setup(tar)
}
wantCredSources := make(map[string]target.CredentialSource)
for _, cl := range tt.args.cls {
cl.TargetId = tar.GetPublicId()
wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = &target.TargetLibrary{
CredentialLibrary: cl.CredentialLibrary,
}
}
if tt.args.addToOrigLibs {
origIds := make([]string, 0, len(origCredSources))
for _, cl := range origCredSources {
origIds = append(origIds, cl.Id())
tt.args.cls = append(tt.args.cls, origCredLibraries...)
for _, cl := range origCredLibraries {
wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = &target.TargetLibrary{
CredentialLibrary: cl.CredentialLibrary,
}
}
tt.args.clIds = append(tt.args.clIds, origIds...)
}
origTarget, _, lookupCredSources, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
require.NoError(err)
assert.Equal(origCredSources, lookupCredSources)
_, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), tar.GetPublicId(), tt.args.targetVersion, tt.args.clIds)
_, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), tar.GetPublicId(), tt.args.targetVersion, tt.args.cls)
if tt.wantErr {
require.Error(err)
assert.Equal(0, affectedRows)
@@ -496,21 +622,15 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
t.Log(err)
require.NoError(err)
assert.Equal(tt.wantAffectedRows, affectedRows)
assert.Equal(len(tt.args.clIds), len(got))
var wantIds []string
wantIds = append(wantIds, tt.args.clIds...)
sort.Strings(wantIds)
assert.Equal(len(wantCredSources), len(got))
var gotIds []string
if len(got) > 0 {
gotIds = make([]string, 0, len(got))
for _, s := range got {
gotIds = append(gotIds, s.Id())
}
for _, cs := range got {
w, ok := wantCredSources[cs.Id()+"_"+string(cs.CredentialPurpose())]
assert.True(ok, "got unexpected credentialsource %v", cs)
assert.Equal(w.Id(), cs.Id())
assert.Equal(w.CredentialPurpose(), cs.CredentialPurpose())
}
sort.Strings(gotIds)
assert.Equal(wantIds, gotIds)
foundTarget, _, _, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
require.NoError(err)
@@ -523,7 +643,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
t.Run("missing-target-id", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "", 1, []string{lib1.PublicId})
cl1 := target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose)
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "", 1, []*target.CredentialLibrary{cl1})
require.Error(err)
assert.Truef(errors.Match(errors.T(errors.InvalidParameter), err), "unexpected error %s", err.Error())
@@ -531,7 +652,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
t.Run("target-not-found", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "fake-target-id", 1, []string{lib1.PublicId})
cl1 := target.TestNewCredentialLibrary("fake-target-id", lib1.PublicId, credential.ApplicationPurpose)
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "fake-target-id", 1, []*target.CredentialLibrary{cl1})
require.Error(err)
assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error())
@@ -5,6 +5,7 @@ import (
"testing"
"time"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/credential/vault"
"github.com/hashicorp/boundary/internal/db"
dbassert "github.com/hashicorp/boundary/internal/db/assert"
@@ -14,6 +15,7 @@ import (
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/store"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -39,9 +41,16 @@ func TestRepository_CreateTarget(t *testing.T) {
cs := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
credSources := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 2)
var clIds []string
var credLibraries []*target.CredentialLibrary
var credLibIds []string
for _, cl := range credSources {
clIds = append(clIds, cl.PublicId)
credLibraries = append(credLibraries, &target.CredentialLibrary{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: cl.PublicId,
CredentialPurpose: string(credential.ApplicationPurpose),
},
})
credLibIds = append(credLibIds, cl.PublicId)
}
type args struct {
@@ -392,11 +401,22 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
cls := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 5)
var testClIds []string
var testCredLibs []*target.CredentialLibrary
for _, cl := range cls {
testCredLibs = append(testCredLibs, &target.CredentialLibrary{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: cl.PublicId,
CredentialPurpose: string(credential.ApplicationPurpose),
},
})
testClIds = append(testClIds, cl.PublicId)
}
tt.newTargetOpts = append(tt.newTargetOpts, target.WithHostSources(testHostSetIds), target.WithCredentialSources(testClIds))
tt.newTargetOpts = append(
tt.newTargetOpts,
target.WithHostSources(testHostSetIds),
target.WithCredentialLibraries(testCredLibs),
)
name := tt.newName
if name == "" {
name = tcp.TestId(t)
+5 -6
View File
@@ -36,12 +36,11 @@ func TestTarget(t *testing.T, conn *db.DB, scopeId, name string, opt ...target.O
err := rw.CreateItems(context.Background(), newHostSets)
require.NoError(err)
}
if len(opts.WithCredentialSources) > 0 {
newCredLibs := make([]interface{}, 0, len(opts.WithCredentialSources))
for _, cl := range opts.WithCredentialSources {
newCl, err := target.NewCredentialLibrary(tar.PublicId, cl)
require.NoError(err)
newCredLibs = append(newCredLibs, newCl)
if len(opts.WithCredentialLibraries) > 0 {
newCredLibs := make([]interface{}, 0, len(opts.WithCredentialLibraries))
for _, cl := range opts.WithCredentialLibraries {
cl.TargetId = tar.PublicId
newCredLibs = append(newCredLibs, cl)
}
err := rw.CreateItems(context.Background(), newCredLibs)
require.NoError(err)
+18 -4
View File
@@ -4,19 +4,33 @@ import (
"context"
"testing"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/target/store"
"github.com/stretchr/testify/require"
)
// TestNewCredentialLibrary creates a new in memory CredentialLibrary
// representing the relationship between targetId and credentialLibraryId with
// the given purpose.
func TestNewCredentialLibrary(targetId, credentialLibraryId string, purpose credential.Purpose) *CredentialLibrary {
return &CredentialLibrary{
CredentialLibrary: &store.CredentialLibrary{
TargetId: targetId,
CredentialLibraryId: credentialLibraryId,
CredentialPurpose: string(purpose),
},
}
}
// TestCredentialLibrary creates a CredentialLibrary for targetId and
// libraryId.
// libraryId with the credential purpose of application.
func TestCredentialLibrary(t *testing.T, conn *db.DB, targetId, libraryId string) *CredentialLibrary {
t.Helper()
require := require.New(t)
rw := db.New(conn)
lib, err := NewCredentialLibrary(targetId, libraryId)
require.NoError(err)
err = rw.Create(context.Background(), lib)
lib := TestNewCredentialLibrary(targetId, libraryId, credential.ApplicationPurpose)
err := rw.Create(context.Background(), lib)
require.NoError(err)
return lib
}