feat(target): Add support for static credential as target credential sources
This commit is contained in:
1 parent
58d546cdd4
commit
00dfea1244
27 files changed
+1951
-588
No files matched your search
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/credential"
|
||||
credstatic "github.com/hashicorp/boundary/internal/credential/static"
|
||||
"github.com/hashicorp/boundary/internal/credential/vault"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/common"
|
||||
@@ -1443,12 +1444,16 @@ func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
credLibs, err := createCredLibs(targetId, applicationIds, nil, egressIds)
|
||||
if err != nil {
|
||||
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err)
|
||||
|
||||
var creds target.CredentialSources
|
||||
if len(applicationIds) > 0 {
|
||||
creds.ApplicationCredentialIds = strutil.RemoveDuplicates(applicationIds, false)
|
||||
}
|
||||
if len(egressIds) > 0 {
|
||||
creds.EgressCredentialIds = strutil.RemoveDuplicates(egressIds, false)
|
||||
}
|
||||
|
||||
out, hs, credSources, err := repo.AddTargetCredentialSources(ctx, targetId, version, credLibs)
|
||||
out, hs, credSources, err := repo.AddTargetCredentialSources(ctx, targetId, version, creds)
|
||||
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)
|
||||
@@ -1466,12 +1471,15 @@ func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
credLibs, err := createCredLibs(targetId, applicationIds, nil, egressIds)
|
||||
if err != nil {
|
||||
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err)
|
||||
var ids target.CredentialSources
|
||||
if len(applicationIds) > 0 {
|
||||
ids.ApplicationCredentialIds = strutil.RemoveDuplicates(applicationIds, false)
|
||||
}
|
||||
if len(egressIds) > 0 {
|
||||
ids.EgressCredentialIds = strutil.RemoveDuplicates(egressIds, false)
|
||||
}
|
||||
|
||||
_, _, _, err = repo.SetTargetCredentialSources(ctx, targetId, version, credLibs)
|
||||
_, _, _, err = repo.SetTargetCredentialSources(ctx, targetId, version, ids)
|
||||
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)
|
||||
@@ -1494,11 +1502,14 @@ func (s Service) removeCredentialSourcesInRepo(ctx context.Context, targetId str
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
credLibs, err := createCredLibs(targetId, applicationIds, nil, egressIds)
|
||||
if err != nil {
|
||||
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err)
|
||||
var ids target.CredentialSources
|
||||
if len(applicationIds) > 0 {
|
||||
ids.ApplicationCredentialIds = strutil.RemoveDuplicates(applicationIds, false)
|
||||
}
|
||||
_, err = repo.DeleteTargetCredentialSources(ctx, targetId, version, credLibs)
|
||||
if len(egressIds) > 0 {
|
||||
ids.EgressCredentialIds = strutil.RemoveDuplicates(egressIds, false)
|
||||
}
|
||||
_, err = repo.DeleteTargetCredentialSources(ctx, targetId, version, ids)
|
||||
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)
|
||||
@@ -1644,6 +1655,7 @@ func toProto(ctx context.Context, in target.Target, hostSources []target.HostSou
|
||||
var appCredSources, egressCredSources []*pb.CredentialSource
|
||||
var appCredSourceIds, egressCredSourceIds []string
|
||||
var appCredLibraries []*pb.CredentialLibrary
|
||||
var appCredLibIds []string
|
||||
|
||||
for _, cs := range credSources {
|
||||
switch cs.CredentialPurpose() {
|
||||
@@ -1655,11 +1667,14 @@ func toProto(ctx context.Context, in target.Target, hostSources []target.HostSou
|
||||
})
|
||||
|
||||
// ApplicationCredentialLibrariesField is deprecated and should only be populated
|
||||
// for application purpose
|
||||
appCredLibraries = append(appCredLibraries, &pb.CredentialLibrary{
|
||||
Id: cs.Id(),
|
||||
CredentialStoreId: cs.CredentialStoreId(),
|
||||
})
|
||||
// for library type sources
|
||||
if cs.Type() == "library" {
|
||||
appCredLibIds = append(appCredLibIds, cs.Id())
|
||||
appCredLibraries = append(appCredLibraries, &pb.CredentialLibrary{
|
||||
Id: cs.Id(),
|
||||
CredentialStoreId: cs.CredentialStoreId(),
|
||||
})
|
||||
}
|
||||
|
||||
case credential.EgressPurpose:
|
||||
egressCredSources = append(egressCredSources, &pb.CredentialSource{
|
||||
@@ -1674,7 +1689,7 @@ func toProto(ctx context.Context, in target.Target, hostSources []target.HostSou
|
||||
}
|
||||
|
||||
if outputFields.Has(globals.ApplicationCredentialLibraryIdsField) {
|
||||
out.ApplicationCredentialLibraryIds = appCredSourceIds
|
||||
out.ApplicationCredentialLibraryIds = appCredLibIds
|
||||
}
|
||||
if outputFields.Has(globals.ApplicationCredentialSourceIdsField) {
|
||||
out.ApplicationCredentialSourceIds = appCredSourceIds
|
||||
@@ -2040,13 +2055,13 @@ func validateAddCredentialSourcesRequest(req *pbs.AddTargetCredentialSourcesRequ
|
||||
badFields[globals.EgressCredentialSourceIdsField] = "Application or Egress Credential Source IDs must be provided."
|
||||
}
|
||||
for _, cl := range req.GetApplicationCredentialSourceIds() {
|
||||
if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix) {
|
||||
if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix, credstatic.CredentialPrefix) {
|
||||
badFields[globals.ApplicationCredentialSourceIdsField] = fmt.Sprintf("Incorrectly formatted credential source identifier %q.", cl)
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, cl := range req.GetEgressCredentialSourceIds() {
|
||||
if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix) {
|
||||
if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix, credstatic.CredentialPrefix) {
|
||||
badFields[globals.EgressCredentialSourceIdsField] = fmt.Sprintf("Incorrectly formatted credential source identifier %q.", cl)
|
||||
break
|
||||
}
|
||||
@@ -2066,13 +2081,13 @@ func validateSetCredentialSourcesRequest(req *pbs.SetTargetCredentialSourcesRequ
|
||||
badFields[globals.VersionField] = "Required field."
|
||||
}
|
||||
for _, cl := range req.GetApplicationCredentialSourceIds() {
|
||||
if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix) {
|
||||
if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix, credstatic.CredentialPrefix) {
|
||||
badFields[globals.ApplicationCredentialSourceIdsField] = fmt.Sprintf("Incorrectly formatted credential source identifier %q.", cl)
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, cl := range req.GetEgressCredentialSourceIds() {
|
||||
if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix) {
|
||||
if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix, credstatic.CredentialPrefix) {
|
||||
badFields[globals.EgressCredentialSourceIdsField] = fmt.Sprintf("Incorrectly formatted credential source identifier %q.", cl)
|
||||
break
|
||||
}
|
||||
@@ -2096,13 +2111,13 @@ func validateRemoveCredentialSourcesRequest(req *pbs.RemoveTargetCredentialSourc
|
||||
badFields[globals.EgressCredentialSourceIdsField] = "Application or Egress Credential Source IDs must be provided."
|
||||
}
|
||||
for _, cl := range req.GetApplicationCredentialSourceIds() {
|
||||
if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix) {
|
||||
if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix, credstatic.CredentialPrefix) {
|
||||
badFields[globals.ApplicationCredentialSourceIdsField] = fmt.Sprintf("Incorrectly formatted credential source identifier %q.", cl)
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, cl := range req.GetEgressCredentialSourceIds() {
|
||||
if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix) {
|
||||
if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix, credstatic.CredentialPrefix) {
|
||||
badFields[globals.EgressCredentialSourceIdsField] = fmt.Sprintf("Incorrectly formatted credential source identifier %q.", cl)
|
||||
break
|
||||
}
|
||||
@@ -2154,26 +2169,6 @@ 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
|
||||
}
|
||||
|
||||
// credentialToProto converts the strongly typed credential.Credential into a known proto.Message.
|
||||
func credentialToProto(ctx context.Context, cred credential.Credential) (*serverpb.Credential, error) {
|
||||
const op = "targets.credentialToProto"
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/credential"
|
||||
credstatic "github.com/hashicorp/boundary/internal/credential/static"
|
||||
"github.com/hashicorp/boundary/internal/credential/vault"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
|
||||
@@ -2241,7 +2242,7 @@ func TestRemoveTargetLibraries(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddTargetSources(t *testing.T) {
|
||||
func TestAddTargetCredentialSources(t *testing.T) {
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
@@ -2256,8 +2257,11 @@ func TestAddTargetSources(t *testing.T) {
|
||||
s, err := testService(t, conn, kms, wrapper)
|
||||
require.NoError(t, err, "Error when getting new target service.")
|
||||
|
||||
store := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
||||
cls := vault.TestCredentialLibraries(t, conn, wrapper, store.GetPublicId(), 2)
|
||||
storeVault := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
||||
cls := vault.TestCredentialLibraries(t, conn, wrapper, storeVault.GetPublicId(), 2)
|
||||
|
||||
storeStatic := credstatic.TestCredentialStore(t, conn, wrapper, proj.GetPublicId())
|
||||
creds := credstatic.TestUsernamePasswordCredentials(t, conn, wrapper, "user", "pass", storeStatic.GetPublicId(), proj.GetPublicId(), 2)
|
||||
|
||||
ctx := context.Background()
|
||||
addCases := []struct {
|
||||
@@ -2265,24 +2269,61 @@ func TestAddTargetSources(t *testing.T) {
|
||||
tar target.Target
|
||||
addSources []string
|
||||
resultSourceIds []string
|
||||
resultLibIds []string
|
||||
}{
|
||||
{
|
||||
name: "Add source on empty target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty for sources"),
|
||||
name: "Add library on empty target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty for lib sources"),
|
||||
addSources: []string{cls[1].GetPublicId()},
|
||||
resultSourceIds: []string{cls[1].GetPublicId()},
|
||||
resultLibIds: []string{cls[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Add source on populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated for sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
name: "Add static cred on empty target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty for static sources"),
|
||||
addSources: []string{creds[1].GetPublicId()},
|
||||
resultSourceIds: []string{creds[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Add library on library populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated for lib-lib 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()},
|
||||
resultLibIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Add duplicated sources on populated target",
|
||||
tar: tcp.TestTarget(ctx, 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()},
|
||||
name: "Add library on static cred populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated for lib-static sources", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
addSources: []string{cls[1].GetPublicId()},
|
||||
resultSourceIds: []string{creds[0].GetPublicId(), cls[1].GetPublicId()},
|
||||
resultLibIds: []string{cls[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Add static cred on library populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated for static-lib sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
addSources: []string{creds[1].GetPublicId()},
|
||||
resultSourceIds: []string{cls[0].GetPublicId(), creds[1].GetPublicId()},
|
||||
resultLibIds: []string{cls[0].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Add static cred on static cred populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated for static-static sources", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
addSources: []string{creds[1].GetPublicId()},
|
||||
resultSourceIds: []string{creds[0].GetPublicId(), creds[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Add duplicated sources on library populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "duplicated for lib sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
addSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId(), creds[1].GetPublicId(), creds[1].GetPublicId()},
|
||||
resultSourceIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId(), creds[1].GetPublicId()},
|
||||
resultLibIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Add duplicated sources on static cred populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "duplicated for static sources", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
addSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId(), creds[1].GetPublicId(), creds[1].GetPublicId()},
|
||||
resultSourceIds: []string{creds[0].GetPublicId(), cls[1].GetPublicId(), creds[1].GetPublicId()},
|
||||
resultLibIds: []string{cls[1].GetPublicId()},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2298,16 +2339,10 @@ func TestAddTargetSources(t *testing.T) {
|
||||
require.NoError(t, err, "Got error: %v", s)
|
||||
|
||||
assert.ElementsMatch(t, tc.resultSourceIds, got.GetItem().GetApplicationCredentialSourceIds())
|
||||
|
||||
assert.Equal(t, len(tc.resultSourceIds), len(got.GetItem().GetApplicationCredentialSources()))
|
||||
|
||||
wantTemplate := &pb.CredentialSource{
|
||||
CredentialStoreId: store.GetPublicId(),
|
||||
}
|
||||
for _, cl := range got.GetItem().GetApplicationCredentialSources() {
|
||||
cl.Id = ""
|
||||
assert.Empty(t, cmp.Diff(wantTemplate, cl, protocmp.Transform()))
|
||||
}
|
||||
assert.ElementsMatch(t, tc.resultLibIds, got.GetItem().GetApplicationCredentialLibraryIds())
|
||||
assert.Equal(t, len(tc.resultLibIds), len(got.GetItem().GetApplicationCredentialLibraries()))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2385,15 +2420,11 @@ func TestSetTargetCredentialSources(t *testing.T) {
|
||||
s, err := testService(t, conn, kms, wrapper)
|
||||
require.NoError(t, err, "Error when getting new target service.")
|
||||
|
||||
store := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
||||
cls := vault.TestCredentialLibraries(t, conn, wrapper, store.GetPublicId(), 2)
|
||||
storeVault := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
||||
cls := vault.TestCredentialLibraries(t, conn, wrapper, storeVault.GetPublicId(), 2)
|
||||
|
||||
resultingTargetSource := func(id string) *pb.CredentialSource {
|
||||
return &pb.CredentialSource{
|
||||
Id: id,
|
||||
CredentialStoreId: store.GetPublicId(),
|
||||
}
|
||||
}
|
||||
storeStatic := credstatic.TestCredentialStore(t, conn, wrapper, proj.GetPublicId())
|
||||
creds := credstatic.TestUsernamePasswordCredentials(t, conn, wrapper, "user", "pass", storeStatic.GetPublicId(), proj.GetPublicId(), 2)
|
||||
|
||||
ctx := context.Background()
|
||||
setCases := []struct {
|
||||
@@ -2402,28 +2433,65 @@ func TestSetTargetCredentialSources(t *testing.T) {
|
||||
setCredentialSources []string
|
||||
resultCredentialSourceIds []string
|
||||
resultCredentialSources []*pb.CredentialLibrary
|
||||
resultLibIds []string
|
||||
}{
|
||||
{
|
||||
name: "Set on empty target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty"),
|
||||
name: "Set libary on empty target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty libary"),
|
||||
setCredentialSources: []string{cls[1].GetPublicId()},
|
||||
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
|
||||
resultLibIds: []string{cls[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Set on populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
name: "Set static on empty target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty static"),
|
||||
setCredentialSources: []string{creds[1].GetPublicId()},
|
||||
resultCredentialSourceIds: []string{creds[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Set library on library populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated libary-libary", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
setCredentialSources: []string{cls[1].GetPublicId()},
|
||||
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
|
||||
resultLibIds: []string{cls[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Set duplicate sources on populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
name: "Set static on library populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated static-libary", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
setCredentialSources: []string{creds[1].GetPublicId()},
|
||||
resultCredentialSourceIds: []string{creds[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Set library on static populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated library-static", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
setCredentialSources: []string{cls[1].GetPublicId()},
|
||||
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
|
||||
resultLibIds: []string{cls[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Set static on static populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated static-static", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
setCredentialSources: []string{creds[1].GetPublicId()},
|
||||
resultCredentialSourceIds: []string{creds[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Set duplicate library on populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "duplicate library", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
setCredentialSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
|
||||
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
|
||||
resultLibIds: []string{cls[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Set empty on populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "another populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
name: "Set duplicate static on populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "duplicate static", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
setCredentialSources: []string{creds[1].GetPublicId(), creds[1].GetPublicId()},
|
||||
resultCredentialSourceIds: []string{creds[1].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Set empty on populated target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "another populated",
|
||||
target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)}),
|
||||
target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
setCredentialSources: []string{},
|
||||
resultCredentialSourceIds: nil,
|
||||
},
|
||||
@@ -2450,9 +2518,7 @@ func TestSetTargetCredentialSources(t *testing.T) {
|
||||
assert.Empty(t, cmp.Diff(tc.resultCredentialSources, got.GetItem().GetApplicationCredentialSourceIds(), protocmp.Transform()))
|
||||
} else {
|
||||
assert.Equal(t, len(tc.resultCredentialSourceIds), len(got.GetItem().GetApplicationCredentialSourceIds()))
|
||||
for _, cl := range got.GetItem().GetApplicationCredentialSources() {
|
||||
assert.Empty(t, cmp.Diff(resultingTargetSource(cl.GetId()), cl, protocmp.Transform()))
|
||||
}
|
||||
assert.Equal(t, len(tc.resultLibIds), len(got.GetItem().GetApplicationCredentialLibraries()))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -2519,8 +2585,11 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
|
||||
s, err := testService(t, conn, kms, wrapper)
|
||||
require.NoError(t, err, "Error when getting new target service.")
|
||||
|
||||
store := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
||||
cls := vault.TestCredentialLibraries(t, conn, wrapper, store.GetPublicId(), 2)
|
||||
csVault := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
||||
cls := vault.TestCredentialLibraries(t, conn, wrapper, csVault.GetPublicId(), 2)
|
||||
|
||||
csStatic := credstatic.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
||||
creds := credstatic.TestUsernamePasswordCredentials(t, conn, wrapper, "u", "p", csStatic.GetPublicId(), proj.GetPublicId(), 2)
|
||||
|
||||
ctx := context.Background()
|
||||
removeCases := []struct {
|
||||
@@ -2529,32 +2598,99 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
|
||||
removeCredentialSources []string
|
||||
resultCredentialSourceIds []string
|
||||
wantErr bool
|
||||
resultLibIds []string
|
||||
}{
|
||||
{
|
||||
name: "Remove from empty",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty"),
|
||||
name: "Remove library from empty",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty lib"),
|
||||
removeCredentialSources: []string{cls[1].GetPublicId()},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Remove 1 of 2 sources",
|
||||
tar: tcp.TestTarget(ctx, 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 static from empty",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty static"),
|
||||
removeCredentialSources: []string{creds[1].GetPublicId()},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Remove 1 duplicate set of 2 sources",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
name: "Remove 1 of 2 libraries",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove partial lib",
|
||||
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()},
|
||||
resultLibIds: []string{cls[0].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Remove 1 of 2 static credentials",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove partial static",
|
||||
target.WithStaticCredentials([]*target.StaticCredential{
|
||||
target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.ApplicationPurpose),
|
||||
target.TestNewStaticCredential("", creds[1].GetPublicId(), credential.ApplicationPurpose),
|
||||
})),
|
||||
removeCredentialSources: []string{creds[1].GetPublicId()},
|
||||
resultCredentialSourceIds: []string{creds[0].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Remove 1 duplicate set of 2 libraries",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove duplicate lib",
|
||||
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(),
|
||||
},
|
||||
resultCredentialSourceIds: []string{cls[0].GetPublicId()},
|
||||
resultLibIds: []string{cls[0].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Remove 1 duplicate set of 2 static credentials",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove duplicate static",
|
||||
target.WithStaticCredentials([]*target.StaticCredential{
|
||||
target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.ApplicationPurpose),
|
||||
target.TestNewStaticCredential("", creds[1].GetPublicId(), credential.ApplicationPurpose),
|
||||
})),
|
||||
removeCredentialSources: []string{
|
||||
creds[1].GetPublicId(), creds[1].GetPublicId(),
|
||||
},
|
||||
resultCredentialSourceIds: []string{creds[0].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Remove mixed sources from target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove mixed",
|
||||
target.WithCredentialLibraries([]*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose),
|
||||
target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose),
|
||||
}),
|
||||
target.WithStaticCredentials([]*target.StaticCredential{
|
||||
target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.ApplicationPurpose),
|
||||
target.TestNewStaticCredential("", creds[1].GetPublicId(), credential.ApplicationPurpose),
|
||||
})),
|
||||
removeCredentialSources: []string{
|
||||
cls[1].GetPublicId(), creds[0].GetPublicId(),
|
||||
},
|
||||
resultCredentialSourceIds: []string{
|
||||
cls[0].GetPublicId(), creds[1].GetPublicId(),
|
||||
},
|
||||
resultLibIds: []string{cls[0].GetPublicId()},
|
||||
},
|
||||
{
|
||||
name: "Remove all sources from target",
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove all", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
|
||||
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove all",
|
||||
target.WithCredentialLibraries([]*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose),
|
||||
target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose),
|
||||
}),
|
||||
target.WithStaticCredentials([]*target.StaticCredential{
|
||||
target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.ApplicationPurpose),
|
||||
target.TestNewStaticCredential("", creds[1].GetPublicId(), credential.ApplicationPurpose),
|
||||
})),
|
||||
removeCredentialSources: []string{
|
||||
cls[0].GetPublicId(), cls[1].GetPublicId(),
|
||||
creds[0].GetPublicId(), creds[1].GetPublicId(),
|
||||
},
|
||||
resultCredentialSourceIds: []string{},
|
||||
},
|
||||
@@ -2576,6 +2712,10 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
|
||||
require.NoError(t, err, "Got error: %v", s)
|
||||
|
||||
assert.ElementsMatch(t, tc.resultCredentialSourceIds, got.GetItem().GetApplicationCredentialSourceIds())
|
||||
assert.Equal(t, len(tc.resultCredentialSourceIds), len(got.GetItem().GetApplicationCredentialSources()))
|
||||
|
||||
assert.ElementsMatch(t, tc.resultLibIds, got.GetItem().GetApplicationCredentialLibraryIds())
|
||||
assert.Equal(t, len(tc.resultLibIds), len(got.GetItem().GetApplicationCredentialLibraries()))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ begin;
|
||||
create trigger immutable_columns before update on target_credential_library
|
||||
for each row execute procedure immutable_columns('target_id', 'credential_library_id', 'credential_purpose', 'create_time');
|
||||
|
||||
-- replaced in 50/02_target.up.sql
|
||||
-- target_library provides the store id along with the other data stored in
|
||||
-- target_credential_library
|
||||
create view target_library
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
begin;
|
||||
|
||||
-- target_static_credential does not follow the normal table naming convention of target_credential_static
|
||||
create table target_static_credential (
|
||||
target_id wt_public_id not null
|
||||
constraint target_fkey
|
||||
references target (public_id)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
credential_static_id wt_public_id not null
|
||||
constraint credential_static_fkey
|
||||
references credential_static (public_id)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
credential_purpose text not null
|
||||
constraint credential_purpose_enm_fkey
|
||||
references credential_purpose_enm (name)
|
||||
on delete restrict
|
||||
on update cascade,
|
||||
create_time wt_timestamp,
|
||||
primary key(target_id, credential_static_id, credential_purpose)
|
||||
);
|
||||
comment on table target_static_credential is
|
||||
'target_static_credential is a join table between the target, credential_static, and credential_purpose_enm tables. '
|
||||
'A row in the target_static_credential table represents the assignment of a static credential to a target for the specified purpose.';
|
||||
|
||||
create trigger default_create_time_column before insert on target_static_credential
|
||||
for each row execute procedure default_create_time();
|
||||
|
||||
create trigger immutable_columns before update on target_static_credential
|
||||
for each row execute procedure immutable_columns('target_id', 'credential_static_id', 'credential_purpose', 'create_time');
|
||||
|
||||
-- replaces view from 10/05_target.up.sql
|
||||
drop view target_library;
|
||||
-- target_credential_source provides the store id along with the other data stored in
|
||||
-- target_credential_library and target_static_credential
|
||||
create view target_credential_source
|
||||
as
|
||||
select
|
||||
tcl.target_id,
|
||||
tcl.credential_library_id as credential_source_id,
|
||||
tcl.credential_purpose,
|
||||
cl.store_id
|
||||
from
|
||||
target_credential_library tcl,
|
||||
credential_library cl
|
||||
where
|
||||
cl.public_id = tcl.credential_library_id
|
||||
union
|
||||
select
|
||||
tcs.target_id,
|
||||
tcs.credential_static_id as credential_source_id,
|
||||
tcs.credential_purpose,
|
||||
cst.store_id
|
||||
from
|
||||
target_static_credential tcs,
|
||||
credential_static cst
|
||||
where
|
||||
cst.public_id = tcs.credential_static_id;
|
||||
comment on view target_credential_source is
|
||||
'target_credential_source is a view where each row contains a credential source and the id of the parent credential store. '
|
||||
'No encrypted data is returned. This view can be used to retrieve data which will be returned external to boundary.';
|
||||
|
||||
create view credential_source_all_types
|
||||
as
|
||||
select
|
||||
public_id,
|
||||
'library' as type
|
||||
from
|
||||
credential_library
|
||||
union
|
||||
select
|
||||
public_id,
|
||||
'static' as type
|
||||
from
|
||||
credential_static;
|
||||
comment on view credential_source_all_types is
|
||||
'credential_source_all_types is a view where each row contains the credential source id and type.';
|
||||
|
||||
commit;
|
||||
@@ -90,3 +90,49 @@ message CredentialLibrary {
|
||||
// @inject_tag: `gorm:"default:current_timestamp"`
|
||||
timestamp.v1.Timestamp create_time = 40;
|
||||
}
|
||||
|
||||
message StaticCredential {
|
||||
// target_id of the Target
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
string target_id = 10;
|
||||
|
||||
// credential_id of the static Credential
|
||||
// @inject_tag: `gorm:"column:credential_static_id;primary_key"
|
||||
string credential_id = 20;
|
||||
|
||||
// credential_purpose is the purpose of the credential for the target
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
string credential_purpose = 30;
|
||||
|
||||
// create_time from the RDBMS
|
||||
// @inject_tag: `gorm:"default:current_timestamp"`
|
||||
timestamp.v1.Timestamp create_time = 40;
|
||||
}
|
||||
|
||||
message CredentialSource {
|
||||
// target_id of the Target
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
string target_id = 10;
|
||||
|
||||
// credential_source_id of the Credential Library or static Credential
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
string credential_source_id = 20;
|
||||
|
||||
// credential_purpose is the purpose of the credential for the target
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
string credential_purpose = 30;
|
||||
|
||||
// create_time from the RDBMS
|
||||
// @inject_tag: `gorm:"default:current_timestamp"`
|
||||
timestamp.v1.Timestamp create_time = 40;
|
||||
}
|
||||
|
||||
message CredentialSourceView {
|
||||
// public_id of the Credential source
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
string public_id = 10;
|
||||
|
||||
// type of credential source (library or static)
|
||||
// @inject_tag: `gorm:"not_null"`
|
||||
string type = 20;
|
||||
}
|
||||
@@ -1442,12 +1442,11 @@ func testSessionCredentialParams(t *testing.T, conn *db.DB, wrapper wrapping.Wra
|
||||
|
||||
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(), cred.ApplicationPurpose),
|
||||
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), cred.ApplicationPurpose),
|
||||
}
|
||||
|
||||
_, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tar.GetPublicId(), tar.GetVersion(), libs)
|
||||
ids := target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{libIds[0].GetPublicId(), libIds[1].GetPublicId()},
|
||||
}
|
||||
_, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tar.GetPublicId(), tar.GetVersion(), ids)
|
||||
require.NoError(err)
|
||||
creds := []*DynamicCredential{
|
||||
NewDynamicCredential(libIds[0].GetPublicId(), cred.ApplicationPurpose),
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package target
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/credential"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/oplog"
|
||||
"github.com/hashicorp/boundary/internal/target/store"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// A StaticCredential is a CredentialSource that represents the relationship
|
||||
// between a target and a static credential.
|
||||
type StaticCredential struct {
|
||||
*store.StaticCredential
|
||||
tableName string `gorm:"-"`
|
||||
}
|
||||
|
||||
// NewStaticCredential creates a new in memory StaticCredential
|
||||
// representing the relationship between targetId and credentialId.
|
||||
func NewStaticCredential(targetId, credentialId string, purpose credential.Purpose) (*StaticCredential, error) {
|
||||
const op = "target.StaticCredential"
|
||||
if targetId == "" {
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "no target id")
|
||||
}
|
||||
if credentialId == "" {
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "no credential id")
|
||||
}
|
||||
|
||||
t := &StaticCredential{
|
||||
StaticCredential: &store.StaticCredential{
|
||||
TargetId: targetId,
|
||||
CredentialId: credentialId,
|
||||
CredentialPurpose: string(purpose),
|
||||
},
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (t *StaticCredential) clone() *StaticCredential {
|
||||
cp := proto.Clone(t.StaticCredential)
|
||||
return &StaticCredential{
|
||||
StaticCredential: cp.(*store.StaticCredential),
|
||||
}
|
||||
}
|
||||
|
||||
// TableName returns the table name.
|
||||
func (t *StaticCredential) TableName() string {
|
||||
if t.tableName != "" {
|
||||
return t.tableName
|
||||
}
|
||||
return "target_static_credential"
|
||||
}
|
||||
|
||||
// SetTableName sets the table name.
|
||||
func (t *StaticCredential) SetTableName(n string) {
|
||||
t.tableName = n
|
||||
}
|
||||
|
||||
func (t *StaticCredential) oplog(op oplog.OpType) oplog.Metadata {
|
||||
metadata := oplog.Metadata{
|
||||
"resource-public-id": []string{fmt.Sprintf("%s:%s:%s", t.TargetId, t.CredentialId, t.CredentialPurpose)},
|
||||
"resource-type": []string{"target-credential-static"},
|
||||
"op-type": []string{op.String()},
|
||||
}
|
||||
return metadata
|
||||
}
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var _ CredentialSource = (*TargetLibrary)(nil)
|
||||
|
||||
// A CredentialLibrary is a CredentialSource that represents the relationship
|
||||
// between a target and a credential library.
|
||||
type CredentialLibrary struct {
|
||||
@@ -74,38 +72,3 @@ func (t *CredentialLibrary) oplog(op oplog.OpType) oplog.Metadata {
|
||||
}
|
||||
return metadata
|
||||
}
|
||||
|
||||
// A TargetLibrary represents the relationship between a target and a
|
||||
// credential library and includes the id of the credential store that the
|
||||
// library is a part of and the library's name and description.
|
||||
//
|
||||
// It implements the target.CredentialSource interface.
|
||||
type TargetLibrary struct {
|
||||
*store.CredentialLibrary
|
||||
StoreId string
|
||||
}
|
||||
|
||||
// TableName returns the tablename to override the default gorm table name
|
||||
func (ts *TargetLibrary) TableName() string {
|
||||
return "target_library"
|
||||
}
|
||||
|
||||
// Id returns the ID of the library
|
||||
func (ts *TargetLibrary) Id() string {
|
||||
return ts.CredentialLibraryId
|
||||
}
|
||||
|
||||
// CredentialStoreId returns the ID of the store containing the library
|
||||
func (ts *TargetLibrary) CredentialStoreId() string {
|
||||
return ts.StoreId
|
||||
}
|
||||
|
||||
// CredentialPurpose returns the purpose of the credential
|
||||
func (ts *TargetLibrary) CredentialPurpose() credential.Purpose {
|
||||
return credential.Purpose(ts.GetCredentialPurpose())
|
||||
}
|
||||
|
||||
// TargetId returns the target linked to this credential source
|
||||
func (ts *TargetLibrary) TargetId() string {
|
||||
return ts.GetTargetId()
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
package target
|
||||
|
||||
import "github.com/hashicorp/boundary/internal/credential"
|
||||
import (
|
||||
"github.com/hashicorp/boundary/internal/credential"
|
||||
"github.com/hashicorp/boundary/internal/target/store"
|
||||
)
|
||||
|
||||
var _ CredentialSource = (*TargetCredentialSource)(nil)
|
||||
|
||||
// CredentialSource is an interface that can be implemented by both a library
|
||||
// and a singular credential.
|
||||
@@ -10,3 +15,57 @@ type CredentialSource interface {
|
||||
CredentialPurpose() credential.Purpose
|
||||
TargetId() string
|
||||
}
|
||||
|
||||
// CredentialSources contains slices of credential publicIds
|
||||
// per purpose to be attacehd to the target.
|
||||
type CredentialSources struct {
|
||||
ApplicationCredentialIds []string
|
||||
EgressCredentialIds []string
|
||||
}
|
||||
|
||||
// A TargetCredentialSource represents the relationship between a target and a
|
||||
// credential library and includes the id of the credential store that the
|
||||
// library is a part of and the library's name and description.
|
||||
//
|
||||
// It implements the target.CredentialSource interface.
|
||||
type TargetCredentialSource struct {
|
||||
*store.CredentialSource
|
||||
StoreId string
|
||||
}
|
||||
|
||||
// TableName returns the tablename to override the default gorm table name
|
||||
func (ts *TargetCredentialSource) TableName() string {
|
||||
return "target_credential_source"
|
||||
}
|
||||
|
||||
// Id returns the ID of the credential source
|
||||
func (ts *TargetCredentialSource) Id() string {
|
||||
return ts.CredentialSourceId
|
||||
}
|
||||
|
||||
// CredentialStoreId returns the ID of the store containing the credential source
|
||||
func (ts *TargetCredentialSource) CredentialStoreId() string {
|
||||
return ts.StoreId
|
||||
}
|
||||
|
||||
// CredentialPurpose returns the purpose of the credential
|
||||
func (ts *TargetCredentialSource) CredentialPurpose() credential.Purpose {
|
||||
return credential.Purpose(ts.GetCredentialPurpose())
|
||||
}
|
||||
|
||||
// TargetId returns the target linked to this credential source
|
||||
func (ts *TargetCredentialSource) TargetId() string {
|
||||
return ts.GetTargetId()
|
||||
}
|
||||
|
||||
// credentialSourceView provides a common way to return credential sources regardless of their
|
||||
// underlying type (library or static).
|
||||
type credentialSourceView struct {
|
||||
*store.CredentialSourceView
|
||||
tableName string `gorm:"-"`
|
||||
}
|
||||
|
||||
// TableName returns the tablename to override the default gorm table name
|
||||
func (csv *credentialSourceView) TableName() string {
|
||||
return "credential_source_all_types"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package target_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/credential"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
"github.com/hashicorp/boundary/internal/target/store"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestStaticCredential_New(t *testing.T) {
|
||||
type args struct {
|
||||
targetId string
|
||||
credId string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *target.StaticCredential
|
||||
wantErr errors.Code
|
||||
}{
|
||||
{
|
||||
name: "no-targetId",
|
||||
args: args{
|
||||
credId: "cred_0000000",
|
||||
},
|
||||
wantErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "no-credId",
|
||||
args: args{
|
||||
targetId: "targ_0000000",
|
||||
},
|
||||
wantErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
args: args{
|
||||
targetId: "targ_0000000",
|
||||
credId: "cred_0000000",
|
||||
},
|
||||
want: &target.StaticCredential{
|
||||
StaticCredential: &store.StaticCredential{
|
||||
TargetId: "targ_0000000",
|
||||
CredentialId: "cred_0000000",
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
got, err := target.NewStaticCredential(tt.args.targetId, tt.args.credId, 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)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
require.NotNil(got)
|
||||
assert.EqualValues(tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ type options struct {
|
||||
WithType subtypes.Subtype
|
||||
WithHostSources []string
|
||||
WithCredentialLibraries []*CredentialLibrary
|
||||
WithStaticCredentials []*StaticCredential
|
||||
WithSessionMaxSeconds uint32
|
||||
WithSessionConnectionLimit int32
|
||||
WithPublicId string
|
||||
@@ -51,6 +52,7 @@ func getDefaultOptions() options {
|
||||
WithType: "",
|
||||
WithHostSources: nil,
|
||||
WithCredentialLibraries: nil,
|
||||
WithStaticCredentials: nil,
|
||||
WithSessionMaxSeconds: uint32((8 * time.Hour).Seconds()),
|
||||
WithSessionConnectionLimit: 1,
|
||||
WithPublicId: "",
|
||||
@@ -137,6 +139,13 @@ func WithCredentialLibraries(cl []*CredentialLibrary) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithStaticCredentials provides an option for providing a list of static credentials.
|
||||
func WithStaticCredentials(c []*StaticCredential) Option {
|
||||
return func(o *options) {
|
||||
o.WithStaticCredentials = c
|
||||
}
|
||||
}
|
||||
|
||||
func WithSessionMaxSeconds(dur uint32) Option {
|
||||
return func(o *options) {
|
||||
o.WithSessionMaxSeconds = dur
|
||||
|
||||
@@ -141,4 +141,37 @@ func Test_GetOpts(t *testing.T) {
|
||||
}
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithStaticCredentials", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := GetOpts(WithStaticCredentials([]*StaticCredential{
|
||||
{
|
||||
StaticCredential: &store.StaticCredential{
|
||||
CredentialId: "alice",
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
{
|
||||
StaticCredential: &store.StaticCredential{
|
||||
CredentialId: "bob",
|
||||
CredentialPurpose: string(credential.EgressPurpose),
|
||||
},
|
||||
},
|
||||
}))
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.WithStaticCredentials = []*StaticCredential{
|
||||
{
|
||||
StaticCredential: &store.StaticCredential{
|
||||
CredentialId: "alice",
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
{
|
||||
StaticCredential: &store.StaticCredential{
|
||||
CredentialId: "bob",
|
||||
CredentialPurpose: string(credential.EgressPurpose),
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
}
|
||||
+28
-23
@@ -3,46 +3,51 @@ package target
|
||||
const (
|
||||
setChangesQuery = `
|
||||
with
|
||||
set_libraries (library_id) as (
|
||||
set_sources (source_id, type) as (
|
||||
-- returns the SET list
|
||||
select public_id
|
||||
from credential_library
|
||||
select public_id, type
|
||||
from credential_source_all_types
|
||||
where public_id in (%s)
|
||||
),
|
||||
current_libraries (library_id) as (
|
||||
current_sources (source_id, type) as (
|
||||
-- returns the current list
|
||||
select credential_library_id
|
||||
select credential_library_id, 'library'
|
||||
from target_credential_library
|
||||
where target_id = @target_id
|
||||
and credential_purpose = @purpose
|
||||
union
|
||||
select credential_static_id, 'static'
|
||||
from target_static_credential
|
||||
where target_id = @target_id
|
||||
and credential_purpose = @purpose
|
||||
),
|
||||
keep_libraries (library_id) as (
|
||||
keep_sources (source_id) as (
|
||||
-- returns the KEEP list
|
||||
select library_id
|
||||
from current_libraries
|
||||
where library_id in (select * from set_libraries)
|
||||
select source_id
|
||||
from current_sources
|
||||
where source_id in (select source_id from set_sources)
|
||||
),
|
||||
delete_libraries (library_id) as (
|
||||
delete_sources (source_id, type) as (
|
||||
-- returns the DELETE list
|
||||
select library_id
|
||||
from current_libraries
|
||||
where library_id not in (select * from set_libraries)
|
||||
select source_id, type
|
||||
from current_sources
|
||||
where source_id not in (select source_id from set_sources)
|
||||
),
|
||||
insert_libraries (library_id) as (
|
||||
insert_sources (source_id, type) as (
|
||||
-- returns the ADD list
|
||||
select library_id
|
||||
from set_libraries
|
||||
where library_id not in (select * from keep_libraries)
|
||||
select source_id, type
|
||||
from set_sources
|
||||
where source_id not in (select * from keep_sources)
|
||||
),
|
||||
final (action, library_id) as (
|
||||
select 'delete', library_id
|
||||
from delete_libraries
|
||||
final (action, source_id, type) as (
|
||||
select 'delete', source_id, type
|
||||
from delete_sources
|
||||
union
|
||||
select 'add', library_id
|
||||
from insert_libraries
|
||||
select 'add', source_id, type
|
||||
from insert_sources
|
||||
)
|
||||
select * from final
|
||||
order by action, library_id;
|
||||
order by action, source_id;
|
||||
`
|
||||
|
||||
targetPublicIdList = `
|
||||
|
||||
@@ -25,9 +25,9 @@ type VetFunc func(context.Context, Target) error
|
||||
// paths are valid and be used to update a target in the Repository.
|
||||
type VetForUpdateFunc func(context.Context, Target, []string) 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
|
||||
// VetCredentialSourcesFunc is a function that checks the given CredentialLibraries
|
||||
// and StaticCredentials to ensure that they are valid for a Target subtype.
|
||||
type VetCredentialSourcesFunc func(context.Context, []*CredentialLibrary, []*StaticCredential) error
|
||||
|
||||
// targetHooks defines the interface containing all the hooks needed for
|
||||
// managing target suptypes.
|
||||
@@ -43,9 +43,9 @@ type targetHooks interface {
|
||||
// and values for updating the database for this type of target given the
|
||||
// field mask paths.
|
||||
VetForUpdate(ctx context.Context, t Target, paths []string) error
|
||||
// VetCredentialLibraries checks that the provided credential
|
||||
// libriaries are properly built for association with a target of this type.
|
||||
VetCredentialLibraries(ctx context.Context, cls []*CredentialLibrary) error
|
||||
// VetCredentialSources checks that the provided credential libriaries and
|
||||
// static credentials are properly built for association with a target of this type.
|
||||
VetCredentialSources(ctx context.Context, cls []*CredentialLibrary, creds []*StaticCredential) error
|
||||
}
|
||||
|
||||
type registryEntry struct {
|
||||
@@ -118,12 +118,13 @@ func (r *registry) vetForUpdateFunc(s subtypes.Subtype) (VetForUpdateFunc, bool)
|
||||
return entry.targetHooks.VetForUpdate, ok
|
||||
}
|
||||
|
||||
func (r *registry) vetCredentialLibrariesFunc(s subtypes.Subtype) (VetCredentialLibrariesFunc, bool) {
|
||||
func (r *registry) vetCredentialSourcesFunc(s subtypes.Subtype) (VetCredentialSourcesFunc, bool) {
|
||||
entry, ok := r.get(s)
|
||||
if !ok {
|
||||
return nil, ok
|
||||
}
|
||||
return entry.targetHooks.VetCredentialLibraries, ok
|
||||
|
||||
return entry.targetHooks.VetCredentialSources, ok
|
||||
}
|
||||
|
||||
func (r *registry) idPrefix(s subtypes.Subtype) (string, bool) {
|
||||
|
||||
@@ -11,41 +11,15 @@ import (
|
||||
"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"
|
||||
"github.com/hashicorp/boundary/internal/types/subtypes"
|
||||
"github.com/hashicorp/go-secure-stdlib/strutil"
|
||||
)
|
||||
|
||||
// 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,
|
||||
// AddTargetCredentialSources adds the credential source ids by purpose to the targetId in the repository.
|
||||
// The target and the list of credential sources attached to the target, after ids 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, cls []*CredentialLibrary, _ ...Option) (Target, []HostSource, []CredentialSource, error) {
|
||||
func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, idsByPurpose CredentialSources, _ ...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")
|
||||
@@ -53,14 +27,6 @@ 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(cls) == 0 {
|
||||
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing credential libraries")
|
||||
}
|
||||
|
||||
addCredLibs := make([]interface{}, 0, len(cls))
|
||||
for _, cl := range cls {
|
||||
addCredLibs = append(addCredLibs, cl)
|
||||
}
|
||||
|
||||
t := allocTargetView()
|
||||
t.PublicId = targetId
|
||||
@@ -74,16 +40,15 @@ 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
|
||||
addCredLibs, addStaticCreds, err := r.createSources(ctx, targetId, t.Subtype(), idsByPurpose)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
target := alloc()
|
||||
target.SetPublicId(ctx, t.PublicId)
|
||||
if err := target.SetPublicId(ctx, t.PublicId); err != nil {
|
||||
return nil, nil, nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
target.SetVersion(targetVersion + 1)
|
||||
metadata = target.Oplog(oplog.OpType_OP_TYPE_UPDATE)
|
||||
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_CREATE.String())
|
||||
@@ -101,7 +66,8 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st
|
||||
db.StdRetryCnt,
|
||||
db.ExpBackoff{},
|
||||
func(reader db.Reader, w db.Writer) error {
|
||||
msgs := make([]*oplog.Message, 0, 2)
|
||||
numOplogMsgs := 1 + len(addCredLibs) + len(addStaticCreds)
|
||||
msgs := make([]*oplog.Message, 0, numOplogMsgs)
|
||||
targetTicket, err := w.GetTicket(ctx, target)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to get ticket"))
|
||||
@@ -120,11 +86,29 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st
|
||||
}
|
||||
msgs = append(msgs, &targetOplogMsg)
|
||||
|
||||
credLibsOplogMsgs := make([]*oplog.Message, 0, len(addCredLibs))
|
||||
if err := w.CreateItems(ctx, addCredLibs, db.NewOplogMsgs(&credLibsOplogMsgs)); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create target credential sources"))
|
||||
if len(addCredLibs) > 0 {
|
||||
i := make([]interface{}, 0, len(addCredLibs))
|
||||
for _, cl := range addCredLibs {
|
||||
i = append(i, cl)
|
||||
}
|
||||
credLibsOplogMsgs := make([]*oplog.Message, 0, len(addCredLibs))
|
||||
if err := w.CreateItems(ctx, i, db.NewOplogMsgs(&credLibsOplogMsgs)); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create target credential library"))
|
||||
}
|
||||
msgs = append(msgs, credLibsOplogMsgs...)
|
||||
}
|
||||
|
||||
if len(addStaticCreds) > 0 {
|
||||
i := make([]interface{}, 0, len(addStaticCreds))
|
||||
for _, c := range addStaticCreds {
|
||||
i = append(i, c)
|
||||
}
|
||||
credStaticOplogMsgs := make([]*oplog.Message, 0, len(addStaticCreds))
|
||||
if err := w.CreateItems(ctx, i, db.NewOplogMsgs(&credStaticOplogMsgs)); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to create target static credential"))
|
||||
}
|
||||
msgs = append(msgs, credStaticOplogMsgs...)
|
||||
}
|
||||
msgs = append(msgs, credLibsOplogMsgs...)
|
||||
|
||||
if err := w.WriteOplogEntryWith(ctx, oplogWrapper, targetTicket, metadata, msgs); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to write oplog"))
|
||||
@@ -148,7 +132,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, cls []*CredentialLibrary, _ ...Option) (int, error) {
|
||||
func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, idsByPurpose CredentialSources, _ ...Option) (int, error) {
|
||||
const op = "target.(Repository).DeleteTargetCredentialSources"
|
||||
if targetId == "" {
|
||||
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target id")
|
||||
@@ -156,14 +140,6 @@ func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId
|
||||
if targetVersion == 0 {
|
||||
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing version")
|
||||
}
|
||||
if len(cls) == 0 {
|
||||
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing credential source ids")
|
||||
}
|
||||
|
||||
deleteCredLibs := make([]interface{}, 0, len(cls))
|
||||
for _, cl := range cls {
|
||||
deleteCredLibs = append(deleteCredLibs, cl)
|
||||
}
|
||||
|
||||
t := allocTargetView()
|
||||
t.PublicId = targetId
|
||||
@@ -172,12 +148,19 @@ func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId
|
||||
}
|
||||
var metadata oplog.Metadata
|
||||
|
||||
deleteCredLibs, deleteStaticCred, err := r.createSources(ctx, targetId, t.Subtype(), idsByPurpose)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
alloc, ok := subtypeRegistry.allocFunc(t.Subtype())
|
||||
if !ok {
|
||||
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type))
|
||||
}
|
||||
target := alloc()
|
||||
target.SetPublicId(ctx, t.PublicId)
|
||||
if err := target.SetPublicId(ctx, t.PublicId); err != nil {
|
||||
return db.NoRowsAffected, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
target.SetVersion(targetVersion + 1)
|
||||
metadata = target.Oplog(oplog.OpType_OP_TYPE_UPDATE)
|
||||
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_DELETE.String())
|
||||
@@ -212,15 +195,41 @@ func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId
|
||||
}
|
||||
msgs = append(msgs, &targetOplogMsg)
|
||||
|
||||
credLibsOplogMsgs := make([]*oplog.Message, 0, len(deleteCredLibs))
|
||||
rowsDeleted, err = w.DeleteItems(ctx, deleteCredLibs, db.NewOplogMsgs(&credLibsOplogMsgs))
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete target credential sources"))
|
||||
if len(deleteCredLibs) > 0 {
|
||||
i := make([]interface{}, 0, len(deleteCredLibs))
|
||||
for _, cl := range deleteCredLibs {
|
||||
i = append(i, cl)
|
||||
}
|
||||
|
||||
credLibsOplogMsgs := make([]*oplog.Message, 0, len(deleteCredLibs))
|
||||
cnt, err := w.DeleteItems(ctx, i, db.NewOplogMsgs(&credLibsOplogMsgs))
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete target credential libraries"))
|
||||
}
|
||||
if cnt != len(deleteCredLibs) {
|
||||
return errors.New(ctx, errors.MultipleRecords, op, fmt.Sprintf("credential libraries deleted %d did not match request for %d", rowsDeleted, len(deleteCredLibs)))
|
||||
}
|
||||
rowsDeleted += cnt
|
||||
msgs = append(msgs, credLibsOplogMsgs...)
|
||||
}
|
||||
if rowsDeleted != len(deleteCredLibs) {
|
||||
return errors.New(ctx, errors.MultipleRecords, op, fmt.Sprintf("credential sources deleted %d did not match request for %d", rowsDeleted, len(deleteCredLibs)))
|
||||
|
||||
if len(deleteStaticCred) > 0 {
|
||||
i := make([]interface{}, 0, len(deleteStaticCred))
|
||||
for _, cl := range deleteStaticCred {
|
||||
i = append(i, cl)
|
||||
}
|
||||
|
||||
staticCredOplogMsgs := make([]*oplog.Message, 0, len(deleteStaticCred))
|
||||
cnt, err := w.DeleteItems(ctx, i, db.NewOplogMsgs(&staticCredOplogMsgs))
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete target static credential"))
|
||||
}
|
||||
if cnt != len(deleteStaticCred) {
|
||||
return errors.New(ctx, errors.MultipleRecords, op, fmt.Sprintf("static credential deleted %d did not match request for %d", rowsDeleted, len(deleteCredLibs)))
|
||||
}
|
||||
rowsDeleted += cnt
|
||||
msgs = append(msgs, staticCredOplogMsgs...)
|
||||
}
|
||||
msgs = append(msgs, credLibsOplogMsgs...)
|
||||
|
||||
if err := w.WriteOplogEntryWith(ctx, oplogWrapper, targetTicket, metadata, msgs); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to write oplog"))
|
||||
@@ -237,7 +246,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, cls []*CredentialLibrary, _ ...Option) ([]HostSource, []CredentialSource, int, error) {
|
||||
func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, ids CredentialSources, _ ...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")
|
||||
@@ -246,19 +255,29 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
|
||||
return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing version")
|
||||
}
|
||||
|
||||
clpm := newCredentialLibrariesPurposeMap(cls)
|
||||
var (
|
||||
addCredLibs []*CredentialLibrary
|
||||
delCredLibs []*CredentialLibrary
|
||||
addStaticCred []*StaticCredential
|
||||
delStaticCred []*StaticCredential
|
||||
)
|
||||
|
||||
var changes []*change
|
||||
|
||||
for purpose, cls := range clpm {
|
||||
c, err := r.changes(ctx, targetId, cls, purpose)
|
||||
byPurpose := map[credential.Purpose][]string{
|
||||
credential.ApplicationPurpose: ids.ApplicationCredentialIds,
|
||||
credential.EgressPurpose: ids.EgressCredentialIds,
|
||||
}
|
||||
for p, ids := range byPurpose {
|
||||
addL, delL, addS, delS, err := r.changes(ctx, targetId, ids, p)
|
||||
if err != nil {
|
||||
return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
changes = append(changes, c...)
|
||||
addCredLibs = append(addCredLibs, addL...)
|
||||
delCredLibs = append(delCredLibs, delL...)
|
||||
addStaticCred = append(addStaticCred, addS...)
|
||||
delStaticCred = append(delStaticCred, delS...)
|
||||
}
|
||||
|
||||
if len(changes) == 0 {
|
||||
if len(addCredLibs)+len(delCredLibs)+len(addStaticCred)+len(delStaticCred) == 0 {
|
||||
// Nothing needs to be changed, return early
|
||||
hostSets, err := fetchHostSources(ctx, r.reader, targetId)
|
||||
if err != nil {
|
||||
@@ -271,16 +290,6 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
|
||||
return hostSets, credSources, db.NoRowsAffected, nil
|
||||
}
|
||||
|
||||
var deleteCredLibs, addCredLibs []interface{}
|
||||
for _, c := range changes {
|
||||
switch c.action {
|
||||
case "delete":
|
||||
deleteCredLibs = append(deleteCredLibs, c.credentialLibrary)
|
||||
case "add":
|
||||
addCredLibs = append(addCredLibs, c.credentialLibrary)
|
||||
}
|
||||
}
|
||||
|
||||
t := allocTargetView()
|
||||
t.PublicId = targetId
|
||||
if err := r.reader.LookupByPublicId(ctx, &t); err != nil {
|
||||
@@ -293,16 +302,19 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
|
||||
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())
|
||||
vetCredentialSources, ok := subtypeRegistry.vetCredentialSourcesFunc(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 {
|
||||
// Validate add sources on target
|
||||
if err := vetCredentialSources(ctx, addCredLibs, addStaticCred); err != nil {
|
||||
return nil, nil, db.NoRowsAffected, err
|
||||
}
|
||||
|
||||
target := alloc()
|
||||
target.SetPublicId(ctx, t.PublicId)
|
||||
if err := target.SetPublicId(ctx, t.PublicId); err != nil {
|
||||
return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
target.SetVersion(targetVersion + 1)
|
||||
metadata = target.Oplog(oplog.OpType_OP_TYPE_UPDATE)
|
||||
|
||||
@@ -340,8 +352,12 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
|
||||
|
||||
// add new credential libraries
|
||||
if len(addCredLibs) > 0 {
|
||||
i := make([]interface{}, 0, len(addCredLibs))
|
||||
for _, cl := range addCredLibs {
|
||||
i = append(i, cl)
|
||||
}
|
||||
addMsgs := make([]*oplog.Message, 0, len(addCredLibs))
|
||||
if err := w.CreateItems(ctx, addCredLibs, db.NewOplogMsgs(&addMsgs)); err != nil {
|
||||
if err := w.CreateItems(ctx, i, db.NewOplogMsgs(&addMsgs)); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to add target credential libraries"))
|
||||
}
|
||||
rowsAffected += len(addMsgs)
|
||||
@@ -350,19 +366,58 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
|
||||
}
|
||||
|
||||
// delete existing credential libraries not part of set
|
||||
if len(deleteCredLibs) > 0 {
|
||||
delMsgs := make([]*oplog.Message, 0, len(deleteCredLibs))
|
||||
rowsDeleted, err := w.DeleteItems(ctx, deleteCredLibs, db.NewOplogMsgs(&delMsgs))
|
||||
if len(delCredLibs) > 0 {
|
||||
i := make([]interface{}, 0, len(delCredLibs))
|
||||
for _, cl := range delCredLibs {
|
||||
i = append(i, cl)
|
||||
}
|
||||
delMsgs := make([]*oplog.Message, 0, len(delCredLibs))
|
||||
rowsDeleted, err := w.DeleteItems(ctx, i, db.NewOplogMsgs(&delMsgs))
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete target credential libraries"))
|
||||
}
|
||||
if rowsDeleted != len(delMsgs) {
|
||||
return errors.New(ctx, errors.MultipleRecords, op, fmt.Sprintf("target credential libraries deleted %d did not match request for %d", rowsDeleted, len(deleteCredLibs)))
|
||||
return errors.New(ctx, errors.MultipleRecords, op, fmt.Sprintf("target credential libraries deleted %d did not match request for %d", rowsDeleted, len(delCredLibs)))
|
||||
}
|
||||
rowsAffected += rowsDeleted
|
||||
msgs = append(msgs, delMsgs...)
|
||||
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_DELETE.String())
|
||||
}
|
||||
|
||||
// add new static credential
|
||||
if len(addStaticCred) > 0 {
|
||||
i := make([]interface{}, 0, len(addStaticCred))
|
||||
for _, cl := range addStaticCred {
|
||||
i = append(i, cl)
|
||||
}
|
||||
addMsgs := make([]*oplog.Message, 0, len(addStaticCred))
|
||||
if err := w.CreateItems(ctx, i, db.NewOplogMsgs(&addMsgs)); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to add target static credential "))
|
||||
}
|
||||
rowsAffected += len(addMsgs)
|
||||
msgs = append(msgs, addMsgs...)
|
||||
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_CREATE.String())
|
||||
}
|
||||
|
||||
// delete existing static credentials not part of set
|
||||
if len(delStaticCred) > 0 {
|
||||
i := make([]interface{}, 0, len(delStaticCred))
|
||||
for _, cl := range delStaticCred {
|
||||
i = append(i, cl)
|
||||
}
|
||||
delMsgs := make([]*oplog.Message, 0, len(delStaticCred))
|
||||
rowsDeleted, err := w.DeleteItems(ctx, i, db.NewOplogMsgs(&delMsgs))
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete target static credential"))
|
||||
}
|
||||
if rowsDeleted != len(delMsgs) {
|
||||
return errors.New(ctx, errors.MultipleRecords, op, fmt.Sprintf("target static credential deleted %d did not match request for %d", rowsDeleted, len(delStaticCred)))
|
||||
}
|
||||
rowsAffected += rowsDeleted
|
||||
msgs = append(msgs, delMsgs...)
|
||||
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_DELETE.String())
|
||||
}
|
||||
|
||||
if err := w.WriteOplogEntryWith(ctx, oplogWrapper, targetTicket, metadata, msgs); err != nil {
|
||||
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to write oplog"))
|
||||
}
|
||||
@@ -384,17 +439,17 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
|
||||
return hostSources, credSources, rowsAffected, nil
|
||||
}
|
||||
|
||||
type change struct {
|
||||
action string
|
||||
credentialLibrary *CredentialLibrary
|
||||
}
|
||||
|
||||
type changeQueryResult struct {
|
||||
Action string
|
||||
LibraryId string
|
||||
Action string
|
||||
Type string
|
||||
SourceId string
|
||||
}
|
||||
|
||||
func (r *Repository) changes(ctx context.Context, targetId string, cls []*CredentialLibrary, purpose string) ([]*change, error) {
|
||||
func (r *Repository) changes(ctx context.Context, targetId string, ids []string, purpose credential.Purpose) (
|
||||
addCredLib, delCredLib []*CredentialLibrary,
|
||||
addStaticCred, delStaticCred []*StaticCredential,
|
||||
err error,
|
||||
) {
|
||||
const op = "target.(Repository).changes"
|
||||
|
||||
// TODO ensure that all cls have the same purpose as the given purpose?
|
||||
@@ -402,8 +457,8 @@ func (r *Repository) changes(ctx context.Context, targetId string, cls []*Creden
|
||||
var inClauseSpots []string
|
||||
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))
|
||||
for idx, id := range ids {
|
||||
params = append(params, sql.Named(fmt.Sprintf("%d", idx+1), id))
|
||||
inClauseSpots = append(inClauseSpots, fmt.Sprintf("@%d", idx+1))
|
||||
}
|
||||
inClause := strings.Join(inClauseSpots, ",")
|
||||
@@ -414,45 +469,121 @@ func (r *Repository) changes(ctx context.Context, targetId string, cls []*Creden
|
||||
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"))
|
||||
return nil, nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("query failed"))
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var changes []*change
|
||||
for rows.Next() {
|
||||
var chg changeQueryResult
|
||||
if err := r.reader.ScanRows(ctx, rows, &chg); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("scan row failed"))
|
||||
return nil, nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("scan row failed"))
|
||||
}
|
||||
switch chg.Type {
|
||||
case "library":
|
||||
lib, err := NewCredentialLibrary(targetId, chg.SourceId, purpose)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
switch chg.Action {
|
||||
case "delete":
|
||||
delCredLib = append(delCredLib, lib)
|
||||
default:
|
||||
addCredLib = append(addCredLib, lib)
|
||||
}
|
||||
case "static":
|
||||
cred, err := NewStaticCredential(targetId, chg.SourceId, purpose)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
switch chg.Action {
|
||||
case "delete":
|
||||
delStaticCred = append(delStaticCred, cred)
|
||||
default:
|
||||
addStaticCred = append(addStaticCred, cred)
|
||||
}
|
||||
}
|
||||
changes = append(changes, &change{
|
||||
action: chg.Action,
|
||||
credentialLibrary: &CredentialLibrary{
|
||||
CredentialLibrary: &store.CredentialLibrary{
|
||||
TargetId: targetId,
|
||||
CredentialLibraryId: chg.LibraryId,
|
||||
CredentialPurpose: purpose,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
return changes, nil
|
||||
return addCredLib, delCredLib, addStaticCred, delStaticCred, nil
|
||||
}
|
||||
|
||||
func fetchCredentialSources(ctx context.Context, r db.Reader, targetId string) ([]CredentialSource, error) {
|
||||
const op = "target.fetchCredentialSources"
|
||||
var libraries []*TargetLibrary
|
||||
if err := r.SearchWhere(ctx, &libraries, "target_id = ?", []interface{}{targetId}); err != nil {
|
||||
var sources []*TargetCredentialSource
|
||||
if err := r.SearchWhere(ctx, &sources, "target_id = ?", []interface{}{targetId}); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
// FIXME: When we have static creds, there will need to be an updated view
|
||||
// that unions between libs and creds, at which point the type above will
|
||||
// change. For now we just take the libraries and wrap them.
|
||||
if len(libraries) == 0 {
|
||||
if len(sources) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
ret := make([]CredentialSource, len(libraries))
|
||||
for i, lib := range libraries {
|
||||
ret[i] = lib
|
||||
ret := make([]CredentialSource, len(sources))
|
||||
for i, source := range sources {
|
||||
ret[i] = source
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *Repository) createSources(ctx context.Context, tId string, tSubtype subtypes.Subtype, credSources CredentialSources) ([]*CredentialLibrary, []*StaticCredential, error) {
|
||||
const op = "target.(Repository).createSources"
|
||||
|
||||
// Get a list of unique ids being attached to the target, to be used for looking up the source type (library or static)
|
||||
ids := make([]string, 0, len(credSources.ApplicationCredentialIds)+len(credSources.EgressCredentialIds))
|
||||
ids = append(ids, credSources.ApplicationCredentialIds...)
|
||||
ids = append(ids, credSources.EgressCredentialIds...)
|
||||
totalCreds := len(ids)
|
||||
ids = strutil.RemoveDuplicates(ids, false)
|
||||
if len(ids) == 0 {
|
||||
return nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing credential sources")
|
||||
}
|
||||
|
||||
// Fetch credentials from database to determine the type of credential
|
||||
var credView []*credentialSourceView
|
||||
if err := r.reader.SearchWhere(ctx, &credView, "public_id in (?)", []interface{}{ids}); err != nil {
|
||||
return nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("can't retrieve credentials"))
|
||||
}
|
||||
if len(ids) != len(credView) {
|
||||
return nil, nil, errors.New(ctx, errors.NotSpecificIntegrity, op,
|
||||
fmt.Sprintf("mismatch between request and returned source ids, expected %d got %d", len(ids), len(credView)))
|
||||
}
|
||||
|
||||
// Create a map between credential source ID and it's type (library or static).
|
||||
// This will allow for a quick lookup when calling the corresponding New below
|
||||
credTypeById := make(map[string]string, len(ids))
|
||||
for _, cv := range credView {
|
||||
credTypeById[cv.GetPublicId()] = cv.GetType()
|
||||
}
|
||||
|
||||
credLibs := make([]*CredentialLibrary, 0, totalCreds)
|
||||
staticCred := make([]*StaticCredential, 0, totalCreds)
|
||||
byPurpose := map[credential.Purpose][]string{
|
||||
credential.ApplicationPurpose: credSources.ApplicationCredentialIds,
|
||||
credential.EgressPurpose: credSources.EgressCredentialIds,
|
||||
}
|
||||
for purpose, ids := range byPurpose {
|
||||
for _, id := range ids {
|
||||
switch credTypeById[id] {
|
||||
case "library":
|
||||
lib, err := NewCredentialLibrary(tId, id, purpose)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
credLibs = append(credLibs, lib)
|
||||
case "static":
|
||||
cred, err := NewStaticCredential(tId, id, purpose)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
staticCred = append(staticCred, cred)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vetCredentialSources, ok := subtypeRegistry.vetCredentialSourcesFunc(tSubtype)
|
||||
if !ok {
|
||||
return nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("is an unsupported target type %s", tSubtype))
|
||||
}
|
||||
if err := vetCredentialSources(ctx, credLibs, staticCred); err != nil {
|
||||
return nil, nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
return credLibs, staticCred, nil
|
||||
}
|
||||
@@ -5,12 +5,14 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/credential"
|
||||
"github.com/hashicorp/boundary/internal/credential/static"
|
||||
"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/store"
|
||||
"github.com/hashicorp/boundary/internal/target/targettest"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -34,8 +36,8 @@ func (h hooks) VetForUpdate(ctx context.Context, t target.Target, paths []string
|
||||
return targettest.VetForUpdate(ctx, t, paths)
|
||||
}
|
||||
|
||||
func (h hooks) VetCredentialLibraries(ctx context.Context, cls []*target.CredentialLibrary) error {
|
||||
return targettest.VetCredentialLibraries(ctx, cls)
|
||||
func (h hooks) VetCredentialSources(ctx context.Context, cls []*target.CredentialLibrary, creds []*target.StaticCredential) error {
|
||||
return targettest.VetCredentialSources(ctx, cls, creds)
|
||||
}
|
||||
|
||||
func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
@@ -52,31 +54,40 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
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)
|
||||
storeVault := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
||||
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, storeVault.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))
|
||||
storeStatic := static.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
||||
credsStatic := static.TestUsernamePasswordCredentials(t, conn, wrapper, "u", "p", storeStatic.GetPublicId(), proj.GetPublicId(), 2)
|
||||
cred1 := credsStatic[0]
|
||||
cred2 := credsStatic[1]
|
||||
|
||||
setupFn := func(tar target.Target) ([]target.CredentialSource, target.CredentialSources) {
|
||||
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, storeVault.GetPublicId(), 5)
|
||||
var ids target.CredentialSources
|
||||
for _, cl := range credLibs {
|
||||
cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), cl.PublicId, credential.ApplicationPurpose))
|
||||
ids.ApplicationCredentialIds = append(ids.ApplicationCredentialIds, cl.GetPublicId())
|
||||
}
|
||||
creds := static.TestUsernamePasswordCredentials(t, conn, wrapper, "u", "p", storeStatic.GetPublicId(), proj.GetPublicId(), 5)
|
||||
for _, cred := range creds {
|
||||
ids.ApplicationCredentialIds = append(ids.ApplicationCredentialIds, cred.GetPublicId())
|
||||
}
|
||||
|
||||
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls)
|
||||
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, ids)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 10, len(created))
|
||||
return created, cls
|
||||
return created, ids
|
||||
}
|
||||
type args struct {
|
||||
targetVersion uint32
|
||||
cls []*target.CredentialLibrary
|
||||
addToOrigLibs bool
|
||||
targetVersion uint32
|
||||
ids target.CredentialSources
|
||||
addToOrigSources bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(target.Target) ([]target.CredentialSource, []*target.CredentialLibrary)
|
||||
setup func(target.Target) ([]target.CredentialSource, target.CredentialSources)
|
||||
args args
|
||||
wantAffectedRows int
|
||||
wantErr bool
|
||||
@@ -87,7 +98,6 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
cls: []*target.CredentialLibrary{},
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 10,
|
||||
@@ -96,62 +106,47 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
name: "no-change",
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
cls: []*target.CredentialLibrary{},
|
||||
addToOrigLibs: true,
|
||||
targetVersion: 2,
|
||||
addToOrigSources: true,
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 0,
|
||||
},
|
||||
{
|
||||
name: "add-cred-sources",
|
||||
name: "add-cred-library",
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
|
||||
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.PublicId, lib2.PublicId},
|
||||
},
|
||||
addToOrigLibs: true,
|
||||
addToOrigSources: true,
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 2,
|
||||
},
|
||||
{
|
||||
name: "add-multiple-purposes",
|
||||
name: "add-cred-static",
|
||||
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),
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{cred1.PublicId, cred2.PublicId},
|
||||
},
|
||||
addToOrigLibs: true,
|
||||
addToOrigSources: true,
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 3,
|
||||
wantAffectedRows: 2,
|
||||
},
|
||||
{
|
||||
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
|
||||
},
|
||||
name: "add-cred-lib-and-static",
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose),
|
||||
target.TestNewCredentialLibrary("", lib2.PublicId, credential.EgressPurpose),
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{cred1.PublicId, lib1.PublicId, cred2.PublicId, lib2.PublicId},
|
||||
},
|
||||
addToOrigLibs: false,
|
||||
addToOrigSources: true,
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 4,
|
||||
@@ -161,11 +156,10 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 0,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
|
||||
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.PublicId, lib2.PublicId},
|
||||
},
|
||||
addToOrigLibs: true,
|
||||
addToOrigSources: true,
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrCode: errors.InvalidParameter,
|
||||
@@ -175,11 +169,10 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 1000,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
|
||||
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.PublicId, lib2.PublicId},
|
||||
},
|
||||
addToOrigLibs: true,
|
||||
addToOrigSources: true,
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrCode: errors.VersionMismatch,
|
||||
@@ -189,15 +182,52 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
|
||||
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.PublicId, lib2.PublicId},
|
||||
},
|
||||
addToOrigLibs: false,
|
||||
addToOrigSources: false,
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 12,
|
||||
},
|
||||
{
|
||||
name: "remove existing and add cred static",
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{cred1.PublicId, cred2.PublicId},
|
||||
},
|
||||
addToOrigSources: false,
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 12,
|
||||
},
|
||||
{
|
||||
name: "remove existing and add cred static and lib",
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{cred1.PublicId, lib2.PublicId},
|
||||
},
|
||||
addToOrigSources: false,
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 12,
|
||||
},
|
||||
{
|
||||
name: "egress-credential-purpose",
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
ids: target.CredentialSources{
|
||||
EgressCredentialIds: []string{lib1.PublicId},
|
||||
},
|
||||
addToOrigSources: true,
|
||||
},
|
||||
wantAffectedRows: 1,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -207,23 +237,28 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
tar := targettest.TestNewTestTarget(ctx, 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.setup != nil {
|
||||
var origCredIds target.CredentialSources
|
||||
origCredSources, origCredIds = tt.setup(tar)
|
||||
|
||||
if tt.args.addToOrigSources {
|
||||
tt.args.ids.ApplicationCredentialIds = append(tt.args.ids.ApplicationCredentialIds, origCredIds.ApplicationCredentialIds...)
|
||||
tt.args.ids.EgressCredentialIds = append(tt.args.ids.EgressCredentialIds, origCredIds.EgressCredentialIds...)
|
||||
}
|
||||
}
|
||||
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,
|
||||
|
||||
byPurpose := map[credential.Purpose][]string{
|
||||
credential.ApplicationPurpose: tt.args.ids.ApplicationCredentialIds,
|
||||
credential.EgressPurpose: tt.args.ids.EgressCredentialIds,
|
||||
}
|
||||
for purpose, ids := range byPurpose {
|
||||
for _, id := range ids {
|
||||
wantCredSources[id+"_"+string(purpose)] = &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: id,
|
||||
CredentialPurpose: string(purpose),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,7 +267,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
require.NoError(err)
|
||||
assert.Equal(origCredSources, lookupCredSources)
|
||||
|
||||
_, got, affectedRows, err := repo.SetTargetCredentialSources(ctx, tar.GetPublicId(), tt.args.targetVersion, tt.args.cls)
|
||||
_, gotSources, affectedRows, err := repo.SetTargetCredentialSources(ctx, tar.GetPublicId(), tt.args.targetVersion, tt.args.ids)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, affectedRows)
|
||||
@@ -243,9 +278,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
require.NoError(err)
|
||||
assert.Equal(tt.wantAffectedRows, affectedRows)
|
||||
|
||||
assert.Equal(len(wantCredSources), len(got))
|
||||
|
||||
for _, cs := range got {
|
||||
for _, cs := range gotSources {
|
||||
w, ok := wantCredSources[cs.Id()+"_"+string(cs.CredentialPurpose())]
|
||||
assert.True(ok, "got unexpected credentialsource %v", cs)
|
||||
assert.Equal(w.Id(), cs.Id())
|
||||
@@ -263,8 +296,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
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})
|
||||
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "", 1,
|
||||
target.CredentialSources{ApplicationCredentialIds: []string{lib1.PublicId}})
|
||||
|
||||
require.Error(err)
|
||||
assert.Truef(errors.Match(errors.T(errors.InvalidParameter), err), "unexpected error %s", err.Error())
|
||||
@@ -272,8 +305,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
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})
|
||||
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "fake-target-id", 1,
|
||||
target.CredentialSources{ApplicationCredentialIds: []string{lib1.PublicId}})
|
||||
|
||||
require.Error(err)
|
||||
assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error())
|
||||
|
||||
@@ -331,6 +331,223 @@ func (x *CredentialLibrary) GetCreateTime() *timestamp.Timestamp {
|
||||
return nil
|
||||
}
|
||||
|
||||
type StaticCredential struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// target_id of the Target
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
TargetId string `protobuf:"bytes,10,opt,name=target_id,json=targetId,proto3" json:"target_id,omitempty" gorm:"primary_key"`
|
||||
// credential_id of the static Credential
|
||||
// @inject_tag: `gorm:"column:credential_static_id;primary_key"
|
||||
CredentialId string `protobuf:"bytes,20,opt,name=credential_id,json=credentialId,proto3" json:"credential_id,omitempty" gorm:"column:credential_static_id;primary_key"`
|
||||
// credential_purpose is the purpose of the credential for the target
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
CredentialPurpose string `protobuf:"bytes,30,opt,name=credential_purpose,json=credentialPurpose,proto3" json:"credential_purpose,omitempty" gorm:"primary_key"`
|
||||
// create_time from the RDBMS
|
||||
// @inject_tag: `gorm:"default:current_timestamp"`
|
||||
CreateTime *timestamp.Timestamp `protobuf:"bytes,40,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty" gorm:"default:current_timestamp"`
|
||||
}
|
||||
|
||||
func (x *StaticCredential) Reset() {
|
||||
*x = StaticCredential{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *StaticCredential) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*StaticCredential) ProtoMessage() {}
|
||||
|
||||
func (x *StaticCredential) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[3]
|
||||
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 StaticCredential.ProtoReflect.Descriptor instead.
|
||||
func (*StaticCredential) Descriptor() ([]byte, []int) {
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *StaticCredential) GetTargetId() string {
|
||||
if x != nil {
|
||||
return x.TargetId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *StaticCredential) GetCredentialId() string {
|
||||
if x != nil {
|
||||
return x.CredentialId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *StaticCredential) GetCredentialPurpose() string {
|
||||
if x != nil {
|
||||
return x.CredentialPurpose
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *StaticCredential) GetCreateTime() *timestamp.Timestamp {
|
||||
if x != nil {
|
||||
return x.CreateTime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CredentialSource struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// target_id of the Target
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
TargetId string `protobuf:"bytes,10,opt,name=target_id,json=targetId,proto3" json:"target_id,omitempty" gorm:"primary_key"`
|
||||
// credential_source_id of the Credential Library or static Credential
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
CredentialSourceId string `protobuf:"bytes,20,opt,name=credential_source_id,json=credentialSourceId,proto3" json:"credential_source_id,omitempty" gorm:"primary_key"`
|
||||
// credential_purpose is the purpose of the credential for the target
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
CredentialPurpose string `protobuf:"bytes,30,opt,name=credential_purpose,json=credentialPurpose,proto3" json:"credential_purpose,omitempty" gorm:"primary_key"`
|
||||
// create_time from the RDBMS
|
||||
// @inject_tag: `gorm:"default:current_timestamp"`
|
||||
CreateTime *timestamp.Timestamp `protobuf:"bytes,40,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty" gorm:"default:current_timestamp"`
|
||||
}
|
||||
|
||||
func (x *CredentialSource) Reset() {
|
||||
*x = CredentialSource{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CredentialSource) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CredentialSource) ProtoMessage() {}
|
||||
|
||||
func (x *CredentialSource) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[4]
|
||||
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 CredentialSource.ProtoReflect.Descriptor instead.
|
||||
func (*CredentialSource) Descriptor() ([]byte, []int) {
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *CredentialSource) GetTargetId() string {
|
||||
if x != nil {
|
||||
return x.TargetId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CredentialSource) GetCredentialSourceId() string {
|
||||
if x != nil {
|
||||
return x.CredentialSourceId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CredentialSource) GetCredentialPurpose() string {
|
||||
if x != nil {
|
||||
return x.CredentialPurpose
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CredentialSource) GetCreateTime() *timestamp.Timestamp {
|
||||
if x != nil {
|
||||
return x.CreateTime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CredentialSourceView struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// public_id of the Credential source
|
||||
// @inject_tag: gorm:"primary_key"
|
||||
PublicId string `protobuf:"bytes,10,opt,name=public_id,json=publicId,proto3" json:"public_id,omitempty" gorm:"primary_key"`
|
||||
// type of credential source (library or static)
|
||||
// @inject_tag: `gorm:"not_null"`
|
||||
Type string `protobuf:"bytes,20,opt,name=type,proto3" json:"type,omitempty" gorm:"not_null"`
|
||||
}
|
||||
|
||||
func (x *CredentialSourceView) Reset() {
|
||||
*x = CredentialSourceView{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CredentialSourceView) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CredentialSourceView) ProtoMessage() {}
|
||||
|
||||
func (x *CredentialSourceView) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_storage_target_store_v1_target_proto_msgTypes[5]
|
||||
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 CredentialSourceView.ProtoReflect.Descriptor instead.
|
||||
func (*CredentialSourceView) Descriptor() ([]byte, []int) {
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *CredentialSourceView) GetPublicId() string {
|
||||
if x != nil {
|
||||
return x.PublicId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CredentialSourceView) GetType() string {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_controller_storage_target_store_v1_target_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{
|
||||
@@ -397,12 +614,43 @@ var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{
|
||||
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, 0x42, 0x3b, 0x5a, 0x39,
|
||||
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, 0x73, 0x74,
|
||||
0x6f, 0x72, 0x65, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xd0, 0x01, 0x0a,
|
||||
0x10, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
|
||||
0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x12, 0x23,
|
||||
0x0a, 0x0d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
|
||||
0x6c, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
|
||||
0x6c, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x11, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x75, 0x72, 0x70, 0x6f,
|
||||
0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d,
|
||||
0x65, 0x18, 0x28, 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, 0x22,
|
||||
0xdd, 0x01, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49,
|
||||
0x64, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x12, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63,
|
||||
0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
|
||||
0x6c, 0x5f, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x11, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x75, 0x72, 0x70, 0x6f,
|
||||
0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d,
|
||||
0x65, 0x18, 0x28, 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, 0x22,
|
||||
0x47, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x56, 0x69, 0x65, 0x77, 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, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x14, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x42, 0x3b, 0x5a, 0x39, 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, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b,
|
||||
0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -417,23 +665,28 @@ func file_controller_storage_target_store_v1_target_proto_rawDescGZIP() []byte {
|
||||
return file_controller_storage_target_store_v1_target_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_controller_storage_target_store_v1_target_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_controller_storage_target_store_v1_target_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_controller_storage_target_store_v1_target_proto_goTypes = []interface{}{
|
||||
(*TargetView)(nil), // 0: controller.storage.target.store.v1.TargetView
|
||||
(*TargetHostSet)(nil), // 1: controller.storage.target.store.v1.TargetHostSet
|
||||
(*CredentialLibrary)(nil), // 2: controller.storage.target.store.v1.CredentialLibrary
|
||||
(*timestamp.Timestamp)(nil), // 3: controller.storage.timestamp.v1.Timestamp
|
||||
(*TargetView)(nil), // 0: controller.storage.target.store.v1.TargetView
|
||||
(*TargetHostSet)(nil), // 1: controller.storage.target.store.v1.TargetHostSet
|
||||
(*CredentialLibrary)(nil), // 2: controller.storage.target.store.v1.CredentialLibrary
|
||||
(*StaticCredential)(nil), // 3: controller.storage.target.store.v1.StaticCredential
|
||||
(*CredentialSource)(nil), // 4: controller.storage.target.store.v1.CredentialSource
|
||||
(*CredentialSourceView)(nil), // 5: controller.storage.target.store.v1.CredentialSourceView
|
||||
(*timestamp.Timestamp)(nil), // 6: controller.storage.timestamp.v1.Timestamp
|
||||
}
|
||||
var file_controller_storage_target_store_v1_target_proto_depIdxs = []int32{
|
||||
3, // 0: controller.storage.target.store.v1.TargetView.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
3, // 1: controller.storage.target.store.v1.TargetView.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
3, // 2: controller.storage.target.store.v1.TargetHostSet.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
3, // 3: controller.storage.target.store.v1.CredentialLibrary.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
4, // [4:4] is the sub-list for method output_type
|
||||
4, // [4:4] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
6, // 0: controller.storage.target.store.v1.TargetView.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
6, // 1: controller.storage.target.store.v1.TargetView.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
6, // 2: controller.storage.target.store.v1.TargetHostSet.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
6, // 3: controller.storage.target.store.v1.CredentialLibrary.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
6, // 4: controller.storage.target.store.v1.StaticCredential.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
6, // 5: controller.storage.target.store.v1.CredentialSource.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
6, // [6:6] is the sub-list for method output_type
|
||||
6, // [6:6] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
6, // [6:6] is the sub-list for extension extendee
|
||||
0, // [0:6] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_controller_storage_target_store_v1_target_proto_init() }
|
||||
@@ -478,6 +731,42 @@ func file_controller_storage_target_store_v1_target_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_controller_storage_target_store_v1_target_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*StaticCredential); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_controller_storage_target_store_v1_target_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CredentialSource); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_controller_storage_target_store_v1_target_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CredentialSourceView); 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{
|
||||
@@ -485,7 +774,7 @@ func file_controller_storage_target_store_v1_target_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_controller_storage_target_store_v1_target_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 3,
|
||||
NumMessages: 6,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -230,8 +230,8 @@ func VetForUpdate(ctx context.Context, t target.Target, paths []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// VetCredentialLibraries allows for any CredentialLibraries.
|
||||
func VetCredentialLibraries(_ context.Context, _ []*target.CredentialLibrary) error {
|
||||
// VetCredentialSources allows for any CredentialLibraries.
|
||||
func VetCredentialSources(_ context.Context, _ []*target.CredentialLibrary, _ []*target.StaticCredential) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -71,13 +71,18 @@ func (h targetHooks) VetForUpdate(ctx context.Context, t target.Target, paths []
|
||||
return nil
|
||||
}
|
||||
|
||||
// VetCredentialLibraries checks that all of the provided credential libriaries have a CredentialPurpose
|
||||
// VetCredentialSources checks that all the provided credential sources have a CredentialPurpose
|
||||
// of ApplicationPurpose. Any other CredentialPurpose will result in an error.
|
||||
func (h targetHooks) VetCredentialLibraries(ctx context.Context, cls []*target.CredentialLibrary) error {
|
||||
const op = "tcp.vetCredentialLibraries"
|
||||
func (h targetHooks) VetCredentialSources(ctx context.Context, libs []*target.CredentialLibrary, creds []*target.StaticCredential) error {
|
||||
const op = "tcp.VetCredentialSources"
|
||||
|
||||
for _, cl := range cls {
|
||||
if cl.CredentialPurpose != string(credential.ApplicationPurpose) {
|
||||
for _, c := range libs {
|
||||
if c.GetCredentialPurpose() != string(credential.ApplicationPurpose) {
|
||||
return errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("tcp.Target only supports credential purpose: %q", credential.ApplicationPurpose))
|
||||
}
|
||||
}
|
||||
for _, c := range creds {
|
||||
if c.GetCredentialPurpose() != string(credential.ApplicationPurpose) {
|
||||
return errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("tcp.Target only supports credential purpose: %q", credential.ApplicationPurpose))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/credential"
|
||||
"github.com/hashicorp/boundary/internal/credential/static"
|
||||
"github.com/hashicorp/boundary/internal/credential/vault"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
@@ -31,16 +32,23 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
|
||||
repo, err := target.NewRepository(rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
|
||||
cs := vault.TestCredentialStores(t, conn, wrapper, staticProj.GetPublicId(), 1)[0]
|
||||
libs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 3)
|
||||
csVault := vault.TestCredentialStores(t, conn, wrapper, staticProj.GetPublicId(), 1)[0]
|
||||
libs := vault.TestCredentialLibraries(t, conn, wrapper, csVault.GetPublicId(), 3)
|
||||
require.Len(t, libs, 3)
|
||||
lib1 := libs[0]
|
||||
lib2 := libs[1]
|
||||
lib3 := libs[2]
|
||||
|
||||
csStatic := static.TestCredentialStore(t, conn, wrapper, staticProj.GetPublicId())
|
||||
creds := static.TestUsernamePasswordCredentials(t, conn, wrapper, "user", "pass", csStatic.GetPublicId(), staticProj.GetPublicId(), 3)
|
||||
require.Len(t, creds, 3)
|
||||
cred1 := creds[0]
|
||||
cred2 := creds[1]
|
||||
cred3 := creds[2]
|
||||
|
||||
type args struct {
|
||||
targetVersion uint32
|
||||
cls []*target.CredentialLibrary
|
||||
ids target.CredentialSources
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -66,18 +74,88 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
|
||||
wantErrCode: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "valid-single-source",
|
||||
name: "valid-single-library",
|
||||
args: args{
|
||||
targetVersion: 1,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
|
||||
},
|
||||
ids: target.CredentialSources{ApplicationCredentialIds: []string{lib1.PublicId}},
|
||||
},
|
||||
wantCredSources: map[string]target.CredentialSource{
|
||||
lib1.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetLibrary{
|
||||
CredentialLibrary: &store.CredentialLibrary{
|
||||
CredentialLibraryId: lib1.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
lib1.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: lib1.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid-single-static",
|
||||
args: args{
|
||||
targetVersion: 1,
|
||||
ids: target.CredentialSources{ApplicationCredentialIds: []string{cred1.PublicId}},
|
||||
},
|
||||
wantCredSources: map[string]target.CredentialSource{
|
||||
cred1.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: cred1.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid-multiple-libraries",
|
||||
args: args{
|
||||
targetVersion: 1,
|
||||
ids: target.CredentialSources{ApplicationCredentialIds: []string{lib1.PublicId, lib2.PublicId, lib3.PublicId}},
|
||||
},
|
||||
wantCredSources: map[string]target.CredentialSource{
|
||||
lib1.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: lib1.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
lib2.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: lib2.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
lib3.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: lib3.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid-multiple-static",
|
||||
args: args{
|
||||
targetVersion: 1,
|
||||
ids: target.CredentialSources{ApplicationCredentialIds: []string{cred1.PublicId, cred2.PublicId, cred3.PublicId}},
|
||||
},
|
||||
wantCredSources: map[string]target.CredentialSource{
|
||||
cred1.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: cred1.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
cred2.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: cred2.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
cred3.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: cred3.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -87,29 +165,33 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
|
||||
name: "valid-multiple-sources",
|
||||
args: args{
|
||||
targetVersion: 1,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
|
||||
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
|
||||
target.TestNewCredentialLibrary("", lib3.PublicId, credential.ApplicationPurpose),
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{cred1.PublicId, cred2.PublicId, lib1.PublicId, lib2.PublicId},
|
||||
},
|
||||
},
|
||||
wantCredSources: map[string]target.CredentialSource{
|
||||
lib1.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetLibrary{
|
||||
CredentialLibrary: &store.CredentialLibrary{
|
||||
CredentialLibraryId: lib1.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
cred1.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: cred1.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
lib2.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetLibrary{
|
||||
CredentialLibrary: &store.CredentialLibrary{
|
||||
CredentialLibraryId: lib2.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
cred2.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: cred2.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
lib3.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetLibrary{
|
||||
CredentialLibrary: &store.CredentialLibrary{
|
||||
CredentialLibraryId: lib3.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
lib1.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: lib1.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
lib2.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: lib2.PublicId,
|
||||
CredentialPurpose: string(credential.ApplicationPurpose),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -119,34 +201,27 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
|
||||
name: "invalid-source-id",
|
||||
args: args{
|
||||
targetVersion: 1,
|
||||
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),
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.PublicId, cred2.PublicId, "invalid-source-id", lib3.PublicId, cred3.PublicId},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrCode: errors.NotSpecificIntegrity,
|
||||
},
|
||||
{
|
||||
name: "egress-credential-purpose",
|
||||
name: "egress-credential-purpose-library",
|
||||
args: args{
|
||||
targetVersion: 1,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose),
|
||||
},
|
||||
ids: target.CredentialSources{EgressCredentialIds: []string{lib1.PublicId}},
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrCode: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "ingress-credential-purpose",
|
||||
name: "egress-credential-purpose-static",
|
||||
args: args{
|
||||
targetVersion: 1,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.IngressPurpose),
|
||||
},
|
||||
ids: target.CredentialSources{EgressCredentialIds: []string{cred1.PublicId}},
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrCode: errors.InvalidParameter,
|
||||
@@ -155,9 +230,7 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
|
||||
name: "bad-version",
|
||||
args: args{
|
||||
targetVersion: 1000,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
|
||||
},
|
||||
ids: target.CredentialSources{ApplicationCredentialIds: []string{lib1.PublicId}},
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrCode: errors.VersionMismatch,
|
||||
@@ -170,11 +243,7 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
projTarget := tcp.TestTarget(ctx, t, conn, staticProj.PublicId, tt.name)
|
||||
|
||||
for _, cl := range tt.args.cls {
|
||||
cl.TargetId = projTarget.GetPublicId()
|
||||
}
|
||||
|
||||
gotTarget, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.GetPublicId(), tt.args.targetVersion, tt.args.cls)
|
||||
gotTarget, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.GetPublicId(), tt.args.targetVersion, tt.args.ids)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErrCode), err), "unexpected error %s", err.Error())
|
||||
@@ -215,22 +284,28 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
projTarget := tcp.TestTarget(ctx, t, conn, staticProj.PublicId, "add-existing")
|
||||
cl1 := target.TestNewCredentialLibrary(projTarget.GetPublicId(), lib1.PublicId, credential.ApplicationPurpose)
|
||||
cl2 := target.TestNewCredentialLibrary(projTarget.GetPublicId(), lib2.PublicId, credential.ApplicationPurpose)
|
||||
cl3 := target.TestNewCredentialLibrary(projTarget.GetPublicId(), lib3.PublicId, credential.ApplicationPurpose)
|
||||
|
||||
_, _, gotCredSources, err := repo.AddTargetCredentialSources(ctx, projTarget.GetPublicId(), 1, []*target.CredentialLibrary{cl1})
|
||||
ids := target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.PublicId},
|
||||
}
|
||||
_, _, gotCredSources, err := repo.AddTargetCredentialSources(ctx, projTarget.GetPublicId(), 1, ids)
|
||||
require.NoError(err)
|
||||
assert.Len(gotCredSources, 1)
|
||||
assert.Equal(lib1.PublicId, gotCredSources[0].Id())
|
||||
|
||||
// Adding lib1 again should error
|
||||
_, _, _, err = repo.AddTargetCredentialSources(ctx, projTarget.GetPublicId(), 2, []*target.CredentialLibrary{cl1})
|
||||
ids = target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.PublicId},
|
||||
}
|
||||
_, _, _, err = repo.AddTargetCredentialSources(ctx, projTarget.GetPublicId(), 2, ids)
|
||||
require.Error(err)
|
||||
assert.True(errors.Match(errors.T(errors.NotUnique), err))
|
||||
|
||||
// Adding multiple with lib1 in set should error
|
||||
_, _, _, err = repo.AddTargetCredentialSources(ctx, projTarget.GetPublicId(), 2, []*target.CredentialLibrary{cl3, cl2, cl1})
|
||||
ids = target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib3.PublicId, lib2.PublicId, lib1.PublicId},
|
||||
}
|
||||
_, _, _, err = repo.AddTargetCredentialSources(ctx, projTarget.GetPublicId(), 2, ids)
|
||||
require.Error(err)
|
||||
assert.True(errors.Match(errors.T(errors.NotUnique), err))
|
||||
|
||||
@@ -243,8 +318,10 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
|
||||
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.AddTargetCredentialSources(context.Background(), "fake-target-id", 1, []*target.CredentialLibrary{cl1})
|
||||
ids := target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.PublicId},
|
||||
}
|
||||
_, _, _, err := repo.AddTargetCredentialSources(context.Background(), "fake-target-id", 1, ids)
|
||||
|
||||
require.Error(err)
|
||||
assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error())
|
||||
@@ -265,8 +342,10 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
|
||||
type args struct {
|
||||
targetIdOverride *string
|
||||
targetVersionOverride *uint32
|
||||
createCnt int
|
||||
deleteCnt int
|
||||
createLibCnt int
|
||||
createStaticCnt int
|
||||
deleteLibCnt int
|
||||
deleteStaticCnt int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -276,27 +355,50 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
|
||||
wantErrCode errors.Code
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
name: "valid-lib-only",
|
||||
args: args{
|
||||
createCnt: 5,
|
||||
deleteCnt: 5,
|
||||
createLibCnt: 5,
|
||||
deleteLibCnt: 5,
|
||||
},
|
||||
wantRowsDeleted: 5,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid-static-only",
|
||||
args: args{
|
||||
createStaticCnt: 5,
|
||||
deleteStaticCnt: 5,
|
||||
},
|
||||
wantRowsDeleted: 5,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid-mixed",
|
||||
args: args{
|
||||
createLibCnt: 5,
|
||||
deleteLibCnt: 5,
|
||||
createStaticCnt: 5,
|
||||
deleteStaticCnt: 5,
|
||||
},
|
||||
wantRowsDeleted: 10,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid-keeping-some",
|
||||
args: args{
|
||||
createCnt: 5,
|
||||
deleteCnt: 2,
|
||||
createLibCnt: 5,
|
||||
deleteLibCnt: 3,
|
||||
createStaticCnt: 5,
|
||||
deleteStaticCnt: 2,
|
||||
},
|
||||
wantRowsDeleted: 2,
|
||||
wantRowsDeleted: 5,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "no-deletes",
|
||||
args: args{
|
||||
createCnt: 5,
|
||||
createLibCnt: 5,
|
||||
createStaticCnt: 5,
|
||||
},
|
||||
wantRowsDeleted: 0,
|
||||
wantErr: true,
|
||||
@@ -306,8 +408,8 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
|
||||
name: "not-found",
|
||||
args: args{
|
||||
targetIdOverride: func() *string { id := tcp.TestId(t); return &id }(),
|
||||
createCnt: 5,
|
||||
deleteCnt: 5,
|
||||
createLibCnt: 5,
|
||||
deleteLibCnt: 5,
|
||||
},
|
||||
wantRowsDeleted: 0,
|
||||
wantErr: true,
|
||||
@@ -317,8 +419,8 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
|
||||
name: "missing-target-id",
|
||||
args: args{
|
||||
targetIdOverride: func() *string { id := ""; return &id }(),
|
||||
createCnt: 5,
|
||||
deleteCnt: 5,
|
||||
createLibCnt: 5,
|
||||
deleteLibCnt: 5,
|
||||
},
|
||||
wantRowsDeleted: 0,
|
||||
wantErr: true,
|
||||
@@ -328,8 +430,8 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
|
||||
name: "zero-version",
|
||||
args: args{
|
||||
targetVersionOverride: func() *uint32 { v := uint32(0); return &v }(),
|
||||
createCnt: 5,
|
||||
deleteCnt: 5,
|
||||
createLibCnt: 5,
|
||||
deleteLibCnt: 5,
|
||||
},
|
||||
wantRowsDeleted: 0,
|
||||
wantErr: true,
|
||||
@@ -339,38 +441,47 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
|
||||
name: "bad-version",
|
||||
args: args{
|
||||
targetVersionOverride: func() *uint32 { v := uint32(1000); return &v }(),
|
||||
createCnt: 5,
|
||||
deleteCnt: 5,
|
||||
createLibCnt: 5,
|
||||
deleteLibCnt: 5,
|
||||
},
|
||||
wantRowsDeleted: 0,
|
||||
wantErr: true,
|
||||
wantErrCode: errors.VersionMismatch,
|
||||
},
|
||||
}
|
||||
css := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), len(tests))
|
||||
csVault := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), len(tests))
|
||||
csStatic := static.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), len(tests))
|
||||
for i, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
cs := css[i]
|
||||
csv := csVault[i]
|
||||
css := csStatic[i]
|
||||
|
||||
ctx := context.Background()
|
||||
tar := tcp.TestTarget(ctx, t, conn, proj.PublicId, tt.name)
|
||||
|
||||
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 {
|
||||
cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), cl.PublicId, credential.ApplicationPurpose))
|
||||
}
|
||||
var ids target.CredentialSources
|
||||
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, csv.PublicId, tt.args.createLibCnt)
|
||||
for _, cl := range credLibs {
|
||||
ids.ApplicationCredentialIds = append(ids.ApplicationCredentialIds, cl.GetPublicId())
|
||||
}
|
||||
creds := static.TestUsernamePasswordCredentials(t, conn, wrapper, "u", "p", css.PublicId, proj.GetPublicId(), tt.args.createStaticCnt)
|
||||
for _, c := range creds {
|
||||
ids.ApplicationCredentialIds = append(ids.ApplicationCredentialIds, c.GetPublicId())
|
||||
}
|
||||
_, _, addedCredSources, err := repo.AddTargetCredentialSources(ctx, tar.GetPublicId(), 1, cls)
|
||||
require.NoError(err)
|
||||
assert.Equal(tt.args.createCnt, len(addedCredSources))
|
||||
|
||||
deleteCredSources := make([]*target.CredentialLibrary, 0, tt.args.deleteCnt)
|
||||
for i := 0; i < tt.args.deleteCnt; i++ {
|
||||
deleteCredSources = append(deleteCredSources, cls[i])
|
||||
_, _, addedCredSources, err := repo.AddTargetCredentialSources(ctx, tar.GetPublicId(), 1, ids)
|
||||
require.NoError(err)
|
||||
assert.Equal(tt.args.createLibCnt+tt.args.createStaticCnt, len(addedCredSources))
|
||||
|
||||
var deleteIds target.CredentialSources
|
||||
for i := 0; i < tt.args.deleteLibCnt; i++ {
|
||||
deleteIds.ApplicationCredentialIds = append(deleteIds.ApplicationCredentialIds, credLibs[i].GetPublicId())
|
||||
}
|
||||
for i := 0; i < tt.args.deleteStaticCnt; i++ {
|
||||
deleteIds.ApplicationCredentialIds = append(deleteIds.ApplicationCredentialIds, creds[i].GetPublicId())
|
||||
}
|
||||
|
||||
var targetId string
|
||||
switch {
|
||||
case tt.args.targetIdOverride != nil:
|
||||
@@ -385,7 +496,7 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
|
||||
default:
|
||||
targetVersion = 2
|
||||
}
|
||||
deletedRows, err := repo.DeleteTargetCredentialSources(ctx, targetId, targetVersion, deleteCredSources)
|
||||
deletedRows, err := repo.DeleteTargetCredentialSources(ctx, targetId, targetVersion, deleteIds)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, deletedRows)
|
||||
@@ -413,22 +524,28 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
projTarget := tcp.TestTarget(ctx, t, conn, proj.PublicId, "add-existing")
|
||||
cl1 := target.TestNewCredentialLibrary(projTarget.GetPublicId(), lib1.PublicId, credential.ApplicationPurpose)
|
||||
cl2 := target.TestNewCredentialLibrary(projTarget.GetPublicId(), lib2.PublicId, credential.ApplicationPurpose)
|
||||
cl3 := target.TestNewCredentialLibrary(projTarget.GetPublicId(), lib3.PublicId, credential.ApplicationPurpose)
|
||||
|
||||
_, _, gotCredSources, err := repo.AddTargetCredentialSources(ctx, projTarget.GetPublicId(), 1, []*target.CredentialLibrary{cl1, cl2})
|
||||
ids := target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.GetPublicId(), lib2.GetPublicId()},
|
||||
}
|
||||
_, _, gotCredSources, err := repo.AddTargetCredentialSources(ctx, projTarget.GetPublicId(), 1, ids)
|
||||
require.NoError(err)
|
||||
assert.Len(gotCredSources, 2)
|
||||
|
||||
// Deleting an unassociated source should return an error
|
||||
delCount, err := repo.DeleteTargetCredentialSources(ctx, projTarget.GetPublicId(), 2, []*target.CredentialLibrary{cl3})
|
||||
delCount, err := repo.DeleteTargetCredentialSources(ctx, projTarget.GetPublicId(), 2,
|
||||
target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib3.GetPublicId()},
|
||||
})
|
||||
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(ctx, projTarget.GetPublicId(), 2, []*target.CredentialLibrary{cl1, cl2, cl3})
|
||||
delCount, err = repo.DeleteTargetCredentialSources(ctx, projTarget.GetPublicId(), 2,
|
||||
target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.GetPublicId(), lib2.GetPublicId(), lib3.GetPublicId()},
|
||||
})
|
||||
require.Error(err)
|
||||
assert.True(errors.Match(errors.T(errors.MultipleRecords), err))
|
||||
assert.Equal(0, delCount)
|
||||
@@ -452,31 +569,40 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
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)
|
||||
storeVault := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
||||
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, storeVault.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))
|
||||
storeStatic := static.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
||||
credsStatic := static.TestUsernamePasswordCredentials(t, conn, wrapper, "u", "p", storeStatic.GetPublicId(), proj.GetPublicId(), 2)
|
||||
cred1 := credsStatic[0]
|
||||
cred2 := credsStatic[1]
|
||||
|
||||
setupFn := func(tar target.Target) ([]target.CredentialSource, target.CredentialSources) {
|
||||
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, storeVault.GetPublicId(), 5)
|
||||
var ids target.CredentialSources
|
||||
for _, cl := range credLibs {
|
||||
cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), cl.PublicId, credential.ApplicationPurpose))
|
||||
ids.ApplicationCredentialIds = append(ids.ApplicationCredentialIds, cl.GetPublicId())
|
||||
}
|
||||
creds := static.TestUsernamePasswordCredentials(t, conn, wrapper, "u", "p", storeStatic.GetPublicId(), proj.GetPublicId(), 5)
|
||||
for _, cred := range creds {
|
||||
ids.ApplicationCredentialIds = append(ids.ApplicationCredentialIds, cred.GetPublicId())
|
||||
}
|
||||
|
||||
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls)
|
||||
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, ids)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 10, len(created))
|
||||
return created, cls
|
||||
return created, ids
|
||||
}
|
||||
type args struct {
|
||||
targetVersion uint32
|
||||
cls []*target.CredentialLibrary
|
||||
addToOrigLibs bool
|
||||
targetVersion uint32
|
||||
ids target.CredentialSources
|
||||
addToOrigSources bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(target.Target) ([]target.CredentialSource, []*target.CredentialLibrary)
|
||||
setup func(target.Target) ([]target.CredentialSource, target.CredentialSources)
|
||||
args args
|
||||
wantAffectedRows int
|
||||
wantErr bool
|
||||
@@ -487,7 +613,6 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
cls: []*target.CredentialLibrary{},
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 10,
|
||||
@@ -496,37 +621,60 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
name: "no-change",
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
cls: []*target.CredentialLibrary{},
|
||||
addToOrigLibs: true,
|
||||
targetVersion: 2,
|
||||
addToOrigSources: true,
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 0,
|
||||
},
|
||||
{
|
||||
name: "add-cred-sources",
|
||||
name: "add-cred-library",
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
|
||||
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.PublicId, lib2.PublicId},
|
||||
},
|
||||
addToOrigLibs: true,
|
||||
addToOrigSources: true,
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 2,
|
||||
},
|
||||
{
|
||||
name: "add-cred-static",
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{cred1.PublicId, cred2.PublicId},
|
||||
},
|
||||
addToOrigSources: true,
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 2,
|
||||
},
|
||||
{
|
||||
name: "add-cred-lib-and-static",
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{cred1.PublicId, lib1.PublicId, cred2.PublicId, lib2.PublicId},
|
||||
},
|
||||
addToOrigSources: true,
|
||||
},
|
||||
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),
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.PublicId, lib2.PublicId},
|
||||
},
|
||||
addToOrigLibs: true,
|
||||
addToOrigSources: true,
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrCode: errors.InvalidParameter,
|
||||
@@ -536,11 +684,10 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 1000,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
|
||||
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.PublicId, lib2.PublicId},
|
||||
},
|
||||
addToOrigLibs: true,
|
||||
addToOrigSources: true,
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrCode: errors.VersionMismatch,
|
||||
@@ -550,38 +697,39 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 2,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
|
||||
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{lib1.PublicId, lib2.PublicId},
|
||||
},
|
||||
addToOrigLibs: false,
|
||||
addToOrigSources: false,
|
||||
},
|
||||
wantErr: false,
|
||||
wantAffectedRows: 12,
|
||||
},
|
||||
{
|
||||
name: "egress-credential-purpose",
|
||||
name: "remove existing and add cred static",
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 1,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose),
|
||||
targetVersion: 2,
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{cred1.PublicId, cred2.PublicId},
|
||||
},
|
||||
addToOrigSources: false,
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrCode: errors.InvalidParameter,
|
||||
wantErr: false,
|
||||
wantAffectedRows: 12,
|
||||
},
|
||||
{
|
||||
name: "ingress-credential-purpose",
|
||||
name: "remove existing and add cred static and lib",
|
||||
setup: setupFn,
|
||||
args: args{
|
||||
targetVersion: 1,
|
||||
cls: []*target.CredentialLibrary{
|
||||
target.TestNewCredentialLibrary("", lib1.PublicId, credential.IngressPurpose),
|
||||
targetVersion: 2,
|
||||
ids: target.CredentialSources{
|
||||
ApplicationCredentialIds: []string{cred1.PublicId, lib2.PublicId},
|
||||
},
|
||||
addToOrigSources: false,
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrCode: errors.InvalidParameter,
|
||||
wantErr: false,
|
||||
wantAffectedRows: 12,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -592,23 +740,28 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
tar := tcp.TestTarget(ctx, 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.setup != nil {
|
||||
var origCredIds target.CredentialSources
|
||||
origCredSources, origCredIds = tt.setup(tar)
|
||||
|
||||
if tt.args.addToOrigSources {
|
||||
tt.args.ids.ApplicationCredentialIds = append(tt.args.ids.ApplicationCredentialIds, origCredIds.ApplicationCredentialIds...)
|
||||
tt.args.ids.EgressCredentialIds = append(tt.args.ids.EgressCredentialIds, origCredIds.EgressCredentialIds...)
|
||||
}
|
||||
}
|
||||
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,
|
||||
|
||||
byPurpose := map[credential.Purpose][]string{
|
||||
credential.ApplicationPurpose: tt.args.ids.ApplicationCredentialIds,
|
||||
credential.EgressPurpose: tt.args.ids.EgressCredentialIds,
|
||||
}
|
||||
for purpose, ids := range byPurpose {
|
||||
for _, id := range ids {
|
||||
wantCredSources[id+"_"+string(purpose)] = &target.TargetCredentialSource{
|
||||
CredentialSource: &store.CredentialSource{
|
||||
CredentialSourceId: id,
|
||||
CredentialPurpose: string(purpose),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -617,7 +770,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
require.NoError(err)
|
||||
assert.Equal(origCredSources, lookupCredSources)
|
||||
|
||||
_, got, affectedRows, err := repo.SetTargetCredentialSources(ctx, tar.GetPublicId(), tt.args.targetVersion, tt.args.cls)
|
||||
_, gotSources, affectedRows, err := repo.SetTargetCredentialSources(ctx, tar.GetPublicId(), tt.args.targetVersion, tt.args.ids)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Equal(0, affectedRows)
|
||||
@@ -628,9 +781,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
require.NoError(err)
|
||||
assert.Equal(tt.wantAffectedRows, affectedRows)
|
||||
|
||||
assert.Equal(len(wantCredSources), len(got))
|
||||
|
||||
for _, cs := range got {
|
||||
for _, cs := range gotSources {
|
||||
w, ok := wantCredSources[cs.Id()+"_"+string(cs.CredentialPurpose())]
|
||||
assert.True(ok, "got unexpected credentialsource %v", cs)
|
||||
assert.Equal(w.Id(), cs.Id())
|
||||
@@ -648,8 +799,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
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})
|
||||
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "", 1,
|
||||
target.CredentialSources{ApplicationCredentialIds: []string{lib1.PublicId}})
|
||||
|
||||
require.Error(err)
|
||||
assert.Truef(errors.Match(errors.T(errors.InvalidParameter), err), "unexpected error %s", err.Error())
|
||||
@@ -657,8 +808,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
||||
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})
|
||||
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "fake-target-id", 1,
|
||||
target.CredentialSources{ApplicationCredentialIds: []string{lib1.PublicId}})
|
||||
|
||||
require.Error(err)
|
||||
assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error())
|
||||
|
||||
@@ -465,7 +465,7 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
|
||||
for _, cl := range credSources {
|
||||
afterUpdateIds = append(afterUpdateIds, cl.Id())
|
||||
}
|
||||
assert.Equal(testClIds, afterUpdateIds)
|
||||
assert.ElementsMatch(testClIds, afterUpdateIds)
|
||||
|
||||
switch tt.name {
|
||||
case "valid-no-op":
|
||||
|
||||
@@ -45,6 +45,15 @@ func TestTarget(ctx context.Context, t testing.TB, conn *db.DB, scopeId, name st
|
||||
err := rw.CreateItems(context.Background(), newCredLibs)
|
||||
require.NoError(err)
|
||||
}
|
||||
if len(opts.WithStaticCredentials) > 0 {
|
||||
newCreds := make([]interface{}, 0, len(opts.WithStaticCredentials))
|
||||
for _, c := range opts.WithStaticCredentials {
|
||||
c.TargetId = tar.GetPublicId()
|
||||
newCreds = append(newCreds, c)
|
||||
}
|
||||
err := rw.CreateItems(context.Background(), newCreds)
|
||||
require.NoError(err)
|
||||
}
|
||||
return tar
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ func Test_TestTcpTarget(t *testing.T) {
|
||||
for _, s := range foundSources {
|
||||
foundIds = append(foundIds, s.Id())
|
||||
}
|
||||
require.Equal(sets, foundIds)
|
||||
require.ElementsMatch(sets, foundIds)
|
||||
}
|
||||
|
||||
func Test_TestCredentialLibrary(t *testing.T) {
|
||||
@@ -80,5 +80,5 @@ func Test_TestCredentialLibrary(t *testing.T) {
|
||||
for _, s := range foundSources {
|
||||
foundIds = append(foundIds, s.Id())
|
||||
}
|
||||
require.Equal(libIds, foundIds)
|
||||
require.ElementsMatch(libIds, foundIds)
|
||||
}
|
||||
@@ -23,6 +23,19 @@ func TestNewCredentialLibrary(targetId, credentialLibraryId string, purpose cred
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewStaticCredential creates a new in memory StaticCredential
|
||||
// representing the relationship between targetId and credentialId with
|
||||
// the given purpose.
|
||||
func TestNewStaticCredential(targetId, credentialId string, purpose credential.Purpose) *StaticCredential {
|
||||
return &StaticCredential{
|
||||
StaticCredential: &store.StaticCredential{
|
||||
TargetId: targetId,
|
||||
CredentialId: credentialId,
|
||||
CredentialPurpose: string(purpose),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TestCredentialLibrary creates a CredentialLibrary for targetId and
|
||||
// libraryId with the credential purpose of application.
|
||||
func TestCredentialLibrary(t testing.TB, conn *db.DB, targetId, libraryId string) *CredentialLibrary {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/credentiallibraries"
|
||||
"github.com/hashicorp/boundary/api/credentials"
|
||||
"github.com/hashicorp/boundary/api/credentialstores"
|
||||
"github.com/hashicorp/boundary/api/hostcatalogs"
|
||||
"github.com/hashicorp/boundary/api/hostsets"
|
||||
@@ -66,11 +67,7 @@ func TestHostSetASD(t *testing.T) {
|
||||
assert.Empty(tar.Item.HostSetIds)
|
||||
}
|
||||
|
||||
func defaultCredLibrary(r *credentiallibraries.CredentialLibrary) *targets.CredentialLibrary {
|
||||
return &targets.CredentialLibrary{Id: r.Id, CredentialStoreId: r.CredentialStoreId}
|
||||
}
|
||||
|
||||
func TestCredentialLibraryASD(t *testing.T) {
|
||||
func TestCredentialSourcesASD(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
tc := controller.NewTestController(t, nil)
|
||||
defer tc.Shutdown()
|
||||
@@ -82,44 +79,85 @@ func TestCredentialLibraryASD(t *testing.T) {
|
||||
client := tc.Client().Clone()
|
||||
client.SetToken(token.Token)
|
||||
|
||||
cs, err := credentialstores.NewClient(client).Create(tc.Context(), "vault", proj.GetPublicId(),
|
||||
csVault, err := credentialstores.NewClient(client).Create(tc.Context(), "vault", proj.GetPublicId(),
|
||||
credentialstores.WithVaultCredentialStoreAddress(vaultServ.Addr), credentialstores.WithVaultCredentialStoreToken(vaultTok))
|
||||
require.NoError(err)
|
||||
require.NotNil(cs)
|
||||
require.NotNil(csVault)
|
||||
|
||||
lClient := credentiallibraries.NewClient(client)
|
||||
r1, err := lClient.Create(tc.Context(), cs.Item.Id, credentiallibraries.WithVaultCredentialLibraryPath("something1"))
|
||||
lib1, err := lClient.Create(tc.Context(), csVault.Item.Id, credentiallibraries.WithVaultCredentialLibraryPath("something1"))
|
||||
require.NoError(err)
|
||||
require.NotNil(r1)
|
||||
require.NotNil(lib1)
|
||||
|
||||
r2, err := lClient.Create(tc.Context(), cs.Item.Id, credentiallibraries.WithVaultCredentialLibraryPath("something2"))
|
||||
lib2, err := lClient.Create(tc.Context(), csVault.Item.Id, credentiallibraries.WithVaultCredentialLibraryPath("something2"))
|
||||
require.NoError(err)
|
||||
require.NotNil(r1)
|
||||
require.NotNil(lib2)
|
||||
|
||||
csStatic, err := credentialstores.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
|
||||
require.NoError(err)
|
||||
require.NotNil(csStatic)
|
||||
|
||||
cClient := credentials.NewClient(client)
|
||||
cOpts := []credentials.Option{credentials.WithUsernamePasswordCredentialUsername("user"), credentials.WithUsernamePasswordCredentialPassword("pass")}
|
||||
cred, err := cClient.Create(tc.Context(), "username_password", csStatic.Item.Id, cOpts...)
|
||||
require.NoError(err)
|
||||
require.NotNil(cred)
|
||||
|
||||
tarClient := targets.NewClient(client)
|
||||
tar, err := tarClient.Create(tc.Context(), "tcp", proj.GetPublicId(), targets.WithName("foo"), targets.WithTcpTargetDefaultPort(2))
|
||||
require.NoError(err)
|
||||
require.NotNil(tar)
|
||||
assert.Empty(tar.Item.ApplicationCredentialLibraryIds)
|
||||
assert.Empty(tar.Item.ApplicationCredentialSourceIds)
|
||||
|
||||
tar, err = tarClient.AddCredentialLibraries(tc.Context(), tar.Item.Id, tar.Item.Version, targets.WithApplicationCredentialLibraryIds([]string{r1.Item.Id}))
|
||||
// Add first Vault library
|
||||
tar, err = tarClient.AddCredentialSources(tc.Context(), tar.Item.Id, tar.Item.Version,
|
||||
targets.WithApplicationCredentialSourceIds([]string{lib1.Item.Id}))
|
||||
require.NoError(err)
|
||||
require.NotNil(tar)
|
||||
assert.ElementsMatch(tar.Item.ApplicationCredentialLibraryIds, []string{r1.Item.Id})
|
||||
assert.ElementsMatch(tar.Item.ApplicationCredentialLibraries, []*targets.CredentialLibrary{defaultCredLibrary(r1.Item)})
|
||||
assert.ElementsMatch(tar.Item.ApplicationCredentialSourceIds, []string{lib1.Item.Id})
|
||||
assert.ElementsMatch(tar.Item.ApplicationCredentialSources, []*targets.CredentialSource{
|
||||
{
|
||||
Id: lib1.Item.Id,
|
||||
CredentialStoreId: csVault.Item.Id,
|
||||
},
|
||||
})
|
||||
|
||||
tar, err = tarClient.SetCredentialLibraries(tc.Context(), tar.Item.Id, tar.Item.Version,
|
||||
targets.WithApplicationCredentialLibraryIds([]string{r2.Item.Id}))
|
||||
// Set second Vault library and a static credential
|
||||
tar, err = tarClient.SetCredentialSources(tc.Context(), tar.Item.Id, tar.Item.Version,
|
||||
targets.WithApplicationCredentialSourceIds([]string{lib2.Item.Id, cred.Item.Id}))
|
||||
require.NoError(err)
|
||||
require.NotNil(tar)
|
||||
assert.ElementsMatch(tar.Item.ApplicationCredentialLibraryIds, []string{r2.Item.Id})
|
||||
assert.ElementsMatch(tar.Item.ApplicationCredentialLibraries, []*targets.CredentialLibrary{defaultCredLibrary(r2.Item)})
|
||||
assert.ElementsMatch(tar.Item.ApplicationCredentialSourceIds, []string{lib2.Item.Id, cred.Item.Id})
|
||||
assert.ElementsMatch(tar.Item.ApplicationCredentialSources, []*targets.CredentialSource{
|
||||
{
|
||||
Id: lib2.Item.Id,
|
||||
CredentialStoreId: csVault.Item.Id,
|
||||
},
|
||||
{
|
||||
Id: cred.Item.Id,
|
||||
CredentialStoreId: csStatic.Item.Id,
|
||||
},
|
||||
})
|
||||
|
||||
tar, err = tarClient.RemoveCredentialLibraries(tc.Context(), tar.Item.Id, tar.Item.Version,
|
||||
targets.WithApplicationCredentialLibraryIds([]string{r2.Item.Id}))
|
||||
// Remove second Vault library
|
||||
tar, err = tarClient.RemoveCredentialSources(tc.Context(), tar.Item.Id, tar.Item.Version,
|
||||
targets.WithApplicationCredentialSourceIds([]string{lib2.Item.Id}))
|
||||
require.NoError(err)
|
||||
require.NotNil(tar)
|
||||
assert.Empty(tar.Item.ApplicationCredentialLibraryIds)
|
||||
assert.ElementsMatch(tar.Item.ApplicationCredentialSourceIds, []string{cred.Item.Id})
|
||||
assert.ElementsMatch(tar.Item.ApplicationCredentialSources, []*targets.CredentialSource{
|
||||
{
|
||||
Id: cred.Item.Id,
|
||||
CredentialStoreId: csStatic.Item.Id,
|
||||
},
|
||||
})
|
||||
|
||||
// Set empty credential sources
|
||||
tar, err = tarClient.SetCredentialSources(tc.Context(), tar.Item.Id, tar.Item.Version,
|
||||
targets.WithApplicationCredentialSourceIds([]string{}))
|
||||
require.NoError(err)
|
||||
require.NotNil(tar)
|
||||
assert.Empty(tar.Item.ApplicationCredentialSourceIds)
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
load _authorized_actions
|
||||
|
||||
function add_target_application_credential_sources() {
|
||||
for i in "${@:2}"
|
||||
do
|
||||
cred+="-application-credential-source $i "
|
||||
done
|
||||
|
||||
boundary targets add-credential-sources -id $1 $cred
|
||||
}
|
||||
|
||||
function remove_target_application_credential_sources() {
|
||||
for i in "${@:2}"
|
||||
do
|
||||
cred+="-application-credential-source $i "
|
||||
done
|
||||
|
||||
boundary targets remove-credential-sources -id $1 $cred
|
||||
}
|
||||
|
||||
function set_target_application_credential_sources() {
|
||||
for i in "${@:2}"
|
||||
do
|
||||
cred+="-application-credential-source $i "
|
||||
done
|
||||
|
||||
boundary targets set-credential-sources -id $1 $cred
|
||||
}
|
||||
|
||||
function validate_credential_sources() {
|
||||
targetData=$(boundary targets read -id $1 -format json)
|
||||
for i in "${@:2}"
|
||||
do
|
||||
if ! echo "$targetData" | grep -q $i; then
|
||||
echo "Credential source id '$i' not found on target"
|
||||
echo "$targetData"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function validate_credential_sources_not_present() {
|
||||
targetData=$(boundary targets read -id $1 -format json)
|
||||
for i in "${@:2}"
|
||||
do
|
||||
if echo "$targetData" | grep -q $i; then
|
||||
echo "Credential source id '$i' unexpectedly found on target"
|
||||
echo "$targetData"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load _auth
|
||||
load _connect
|
||||
load _targets
|
||||
load _helpers
|
||||
load _credential_stores
|
||||
load _credentials
|
||||
load _target_credential_sources
|
||||
|
||||
export NEW_STORE='test-for-add-credential-sources'
|
||||
export NEW_CREDENTIAL='first-credential'
|
||||
export NEW_CREDENTIAL1='second-credential'
|
||||
export NEW_CREDENTIAL2='third-credential'
|
||||
|
||||
@test "boundary/login: can login as admin user" {
|
||||
run login $DEFAULT_LOGIN
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/credential-stores: can create $NEW_STORE static store in default project" {
|
||||
run create_static_credential_store $NEW_STORE $DEFAULT_P_ID
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/credentials: can create $NEW_CREDENTIAL credential in $NEW_STORE store" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
run create_username_password_credential $NEW_CREDENTIAL $csid 'username' 'password'
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: can add $NEW_CREDENTIAL credential source" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
run add_target_application_credential_sources $DEFAULT_TARGET $cid
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: validate only $NEW_CREDENTIAL credential source present" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
run validate_credential_sources $DEFAULT_TARGET $cid
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: cannot add duplicate credential source" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
run add_target_application_credential_sources $DEFAULT_TARGET $cid
|
||||
echo "$output"
|
||||
[ "$status" -eq 1 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: can delete $NEW_CREDENTIAL credential source" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
run remove_target_application_credential_sources $DEFAULT_TARGET $cid
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: validate $NEW_CREDENTIAL credential source removed" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
run validate_credential_sources_not_present $DEFAULT_TARGET $cid
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/credentials: can create additional credentials in $NEW_STORE store" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
run create_username_password_credential $NEW_CREDENTIAL1 $csid 'username' 'password'
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run create_username_password_credential $NEW_CREDENTIAL2 $csid 'username' 'password'
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: can add multiple credential sources" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
local cid1=$(credential_id $NEW_CREDENTIAL1 $csid)
|
||||
local cid2=$(credential_id $NEW_CREDENTIAL2 $csid)
|
||||
run add_target_application_credential_sources $DEFAULT_TARGET $cid $cid1 $cid2
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: validate added credential sources present" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
local cid1=$(credential_id $NEW_CREDENTIAL1 $csid)
|
||||
local cid2=$(credential_id $NEW_CREDENTIAL2 $csid)
|
||||
run validate_credential_sources $DEFAULT_TARGET $cid $cid1 $cid2
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: can delete multiple credential sources" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
local cid1=$(credential_id $NEW_CREDENTIAL1 $csid)
|
||||
run remove_target_application_credential_sources $DEFAULT_TARGET $cid $cid1
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: validate $NEW_CREDENTIAL2 credential source present" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid2=$(credential_id $NEW_CREDENTIAL2 $csid)
|
||||
run validate_credential_sources $DEFAULT_TARGET $cid2
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: validate deleted credential sources not present" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
local cid1=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
run validate_credential_sources_not_present $DEFAULT_TARGET $cid $cid1
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: can set multiple credential sources" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
local cid1=$(credential_id $NEW_CREDENTIAL1 $csid)
|
||||
local cid2=$(credential_id $NEW_CREDENTIAL2 $csid)
|
||||
run set_target_application_credential_sources $DEFAULT_TARGET $cid $cid1 $cid2
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: validate set credential sources present" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
local cid1=$(credential_id $NEW_CREDENTIAL1 $csid)
|
||||
local cid2=$(credential_id $NEW_CREDENTIAL2 $csid)
|
||||
run validate_credential_sources $DEFAULT_TARGET $cid2
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: can set just $NEW_CREDENTIAL credential source" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
run set_target_application_credential_sources $DEFAULT_TARGET $cid
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: validate $NEW_CREDENTIAL credential source present" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid=$(credential_id $NEW_CREDENTIAL $csid)
|
||||
run validate_credential_sources $DEFAULT_TARGET $cid
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "boundary/target: validate not set credential sources not present" {
|
||||
local csid=$(credential_store_id $NEW_STORE $DEFAULT_P_ID)
|
||||
local cid1=$(credential_id $NEW_CREDENTIAL1 $csid)
|
||||
local cid2=$(credential_id $NEW_CREDENTIAL2 $csid)
|
||||
run validate_credential_sources_not_present $DEFAULT_TARGET $cid1 $cid2
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
Reference in new issue
Block a user