refact(target): Change repository to take CredentialLibraries
This change removes the hard-coded credential purpose for the Credential Libraries. It also moves the logic of creating CredentialLibraries from CredentialSources out of the repository and into the targets.Service. This refactor will allow for additional credential purposes to be supported in both the service and the repository.
This commit is contained in:
20 files changed
+1213
-133
No files matched your search
@@ -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
|
||||
|
||||
@@ -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,21 @@ 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[0].GetPublicId(), credential.IngressPurpose),
|
||||
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), credential.EgressPurpose),
|
||||
}
|
||||
|
||||
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[0].GetPublicId(), credential.IngressPurpose),
|
||||
session.NewDynamicCredential(libIds[1].GetPublicId(), credential.EgressPurpose),
|
||||
}
|
||||
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(),
|
||||
},
|
||||
|
||||
@@ -1649,21 +1649,28 @@ 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[0].GetPublicId(), credential.IngressPurpose),
|
||||
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), credential.EgressPurpose),
|
||||
}
|
||||
|
||||
_, _, _, 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[0].GetPublicId(), credential.IngressPurpose),
|
||||
NewDynamicCredential(libIds[1].GetPublicId(), credential.EgressPurpose),
|
||||
}
|
||||
params.DynamicCredentials = creds
|
||||
return params
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -115,7 +140,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 +148,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 +229,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 +238,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 +265,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,28 +368,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 +403,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,254 @@
|
||||
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.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.CredentialLibrary)
|
||||
for _, cl := range tt.args.cls {
|
||||
cl.TargetId = tar.GetPublicId()
|
||||
wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = cl
|
||||
}
|
||||
if tt.args.addToOrigLibs {
|
||||
tt.args.cls = append(tt.args.cls, origCredLibraries...)
|
||||
for _, cl := range origCredLibraries {
|
||||
wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = cl
|
||||
}
|
||||
}
|
||||
|
||||
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.CredentialLibraryId, cs.Id())
|
||||
assert.Equal(w.CredentialPurpose, string(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
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"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"
|
||||
@@ -106,7 +107,12 @@ 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)
|
||||
credLibs := make([]*target.CredentialLibrary, 0, len(tt.args.credLibIds))
|
||||
for _, clid := range tt.args.credLibIds {
|
||||
credLibs = append(credLibs, target.TestNewCredentialLibrary(projTarget.PublicId, clid, credential.ApplicationPurpose))
|
||||
}
|
||||
|
||||
gotTarget, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, tt.args.targetVersion, credLibs)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrCode), err), "unexpected error %s", err.Error())
|
||||
@@ -142,18 +148,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 +176,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 +286,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 +328,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 +344,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,17 +388,17 @@ 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
|
||||
@@ -392,7 +407,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(target.Target) []target.CredentialSource
|
||||
setup func(target.Target) ([]target.CredentialSource, []*target.CredentialLibrary)
|
||||
args args
|
||||
wantAffectedRows int
|
||||
wantErr bool
|
||||
@@ -471,22 +486,29 @@ 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)
|
||||
}
|
||||
|
||||
cls := make([]*target.CredentialLibrary, 0, len(tt.args.clIds))
|
||||
for _, clid := range tt.args.clIds {
|
||||
cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), clid, credential.ApplicationPurpose))
|
||||
}
|
||||
var wantIds []string
|
||||
wantIds = append(wantIds, tt.args.clIds...)
|
||||
if tt.args.addToOrigLibs {
|
||||
origIds := make([]string, 0, len(origCredSources))
|
||||
for _, cl := range origCredSources {
|
||||
origIds = append(origIds, cl.Id())
|
||||
cls = append(cls, origCredLibraries...)
|
||||
for _, cl := range origCredLibraries {
|
||||
wantIds = append(wantIds, cl.CredentialLibraryId)
|
||||
}
|
||||
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, cls)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, affectedRows)
|
||||
@@ -496,10 +518,8 @@ 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...)
|
||||
assert.Equal(len(wantIds), len(got))
|
||||
sort.Strings(wantIds)
|
||||
|
||||
var gotIds []string
|
||||
@@ -523,7 +543,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 +552,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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user