From c9a189a18e8c86b631dd2fbecc53f7b2a81cb367 Mon Sep 17 00:00:00 2001 From: Louis Ruch Date: Thu, 28 Oct 2021 09:45:58 -0700 Subject: [PATCH 01/15] test(kms): Add missing tests and fixup some log lines (#1645) --- internal/kms/immutable_fields_test.go | 571 +++++++++++++++++++++++- internal/kms/repository_database_key.go | 2 +- internal/kms/repository_oidc_key.go | 2 +- internal/kms/testing.go | 2 +- 4 files changed, 568 insertions(+), 9 deletions(-) diff --git a/internal/kms/immutable_fields_test.go b/internal/kms/immutable_fields_test.go index 4662c3fa9..12f38ed09 100644 --- a/internal/kms/immutable_fields_test.go +++ b/internal/kms/immutable_fields_test.go @@ -14,12 +14,503 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" ) -// TODO (jimlambrt 8/2020) define tests for immutable fields in the remaining -// kms tables: -// kms_oplog_key -// kms_oplog_key_version -// kms_session_key -// kms_session_key_version +func TestOplogKey_ImmutableFields(t *testing.T) { + t.Parallel() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + + ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} + + wrapper := db.TestWrapper(t) + org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) + require.NoError(t, conn.Where("1=1").Delete(kms.AllocRootKey()).Error) + require.NoError(t, conn.Where("1=1").Delete(kms.AllocOplogKey()).Error) + rk := kms.TestRootKey(t, conn, org.PublicId) + new := kms.TestOplogKey(t, conn, rk.PrivateId) + + tests := []struct { + name string + update *kms.OplogKey + fieldMask []string + }{ + { + name: "private_id", + update: func() *kms.OplogKey { + k := new.Clone().(*kms.OplogKey) + k.PrivateId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"PrivateId"}, + }, + { + name: "create time", + update: func() *kms.OplogKey { + k := new.Clone().(*kms.OplogKey) + k.CreateTime = &ts + return k + }(), + fieldMask: []string{"CreateTime"}, + }, + { + name: "root_key_id", + update: func() *kms.OplogKey { + k := new.Clone().(*kms.OplogKey) + k.RootKeyId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"ScopeId"}, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + orig := new.Clone() + err := rw.LookupById(context.Background(), orig) + require.NoError(err) + + rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) + require.Error(err) + assert.Equal(0, rowsUpdated) + + after := new.Clone() + err = rw.LookupById(context.Background(), after) + require.NoError(err) + + assert.True(proto.Equal(orig.(*kms.OplogKey), after.(*kms.OplogKey))) + }) + } +} + +func TestOplogKeyVersion_ImmutableFields(t *testing.T) { + t.Parallel() + conn, _ := db.TestSetup(t, "postgres") + wrapper := db.TestWrapper(t) + rw := db.New(conn) + + ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} + + org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) + require.NoError(t, conn.Where("1=1").Delete(kms.AllocRootKey()).Error) + rk := kms.TestRootKey(t, conn, org.PublicId) + _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) + dk := kms.TestOplogKey(t, conn, rk.PrivateId) + new := kms.TestOplogKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("oplog key")) + + tests := []struct { + name string + update *kms.OplogKeyVersion + fieldMask []string + }{ + { + name: "private_id", + update: func() *kms.OplogKeyVersion { + k := new.Clone().(*kms.OplogKeyVersion) + k.PrivateId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"PrivateId"}, + }, + { + name: "create time", + update: func() *kms.OplogKeyVersion { + k := new.Clone().(*kms.OplogKeyVersion) + k.CreateTime = &ts + return k + }(), + fieldMask: []string{"CreateTime"}, + }, + { + name: "oplog_key_id", + update: func() *kms.OplogKeyVersion { + k := new.Clone().(*kms.OplogKeyVersion) + k.OplogKeyId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"RootKeyId"}, + }, + { + name: "root_key_version_id", + update: func() *kms.OplogKeyVersion { + k := new.Clone().(*kms.OplogKeyVersion) + k.RootKeyVersionId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"RootKeyId"}, + }, + { + name: "version", + update: func() *kms.OplogKeyVersion { + k := new.Clone().(*kms.OplogKeyVersion) + k.Version = uint32(22) + return k + }(), + fieldMask: []string{"Version"}, + }, + { + name: "key", + update: func() *kms.OplogKeyVersion { + k := new.Clone().(*kms.OplogKeyVersion) + k.Key = []byte("updated key") + return k + }(), + fieldMask: []string{"CtKey"}, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + orig := new.Clone() + err := rw.LookupById(context.Background(), orig) + require.NoError(err) + + err = tt.update.Encrypt(context.Background(), wrapper) + require.NoError(err) + rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) + require.Error(err) + assert.Equal(0, rowsUpdated) + + after := new.Clone() + err = rw.LookupById(context.Background(), after) + require.NoError(err) + + assert.True(proto.Equal(orig.(*kms.OplogKeyVersion), after.(*kms.OplogKeyVersion))) + }) + } +} + +func TestTokenKey_ImmutableFields(t *testing.T) { + t.Parallel() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + + ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} + + wrapper := db.TestWrapper(t) + org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) + require.NoError(t, conn.Where("1=1").Delete(kms.AllocRootKey()).Error) + require.NoError(t, conn.Where("1=1").Delete(kms.AllocTokenKey()).Error) + rk := kms.TestRootKey(t, conn, org.PublicId) + new := kms.TestTokenKey(t, conn, rk.PrivateId) + + tests := []struct { + name string + update *kms.TokenKey + fieldMask []string + }{ + { + name: "private_id", + update: func() *kms.TokenKey { + k := new.Clone().(*kms.TokenKey) + k.PrivateId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"PrivateId"}, + }, + { + name: "create time", + update: func() *kms.TokenKey { + k := new.Clone().(*kms.TokenKey) + k.CreateTime = &ts + return k + }(), + fieldMask: []string{"CreateTime"}, + }, + { + name: "root_key_id", + update: func() *kms.TokenKey { + k := new.Clone().(*kms.TokenKey) + k.RootKeyId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"ScopeId"}, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + orig := new.Clone() + err := rw.LookupById(context.Background(), orig) + require.NoError(err) + + rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) + require.Error(err) + assert.Equal(0, rowsUpdated) + + after := new.Clone() + err = rw.LookupById(context.Background(), after) + require.NoError(err) + + assert.True(proto.Equal(orig.(*kms.TokenKey), after.(*kms.TokenKey))) + }) + } +} + +func TestTokenKeyVersion_ImmutableFields(t *testing.T) { + t.Parallel() + conn, _ := db.TestSetup(t, "postgres") + wrapper := db.TestWrapper(t) + rw := db.New(conn) + + ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} + + org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) + require.NoError(t, conn.Where("1=1").Delete(kms.AllocRootKey()).Error) + rk := kms.TestRootKey(t, conn, org.PublicId) + _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) + dk := kms.TestTokenKey(t, conn, rk.PrivateId) + new := kms.TestTokenKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("token key")) + + tests := []struct { + name string + update *kms.TokenKeyVersion + fieldMask []string + }{ + { + name: "private_id", + update: func() *kms.TokenKeyVersion { + k := new.Clone().(*kms.TokenKeyVersion) + k.PrivateId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"PrivateId"}, + }, + { + name: "create time", + update: func() *kms.TokenKeyVersion { + k := new.Clone().(*kms.TokenKeyVersion) + k.CreateTime = &ts + return k + }(), + fieldMask: []string{"CreateTime"}, + }, + { + name: "token_key_id", + update: func() *kms.TokenKeyVersion { + k := new.Clone().(*kms.TokenKeyVersion) + k.TokenKeyId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"RootKeyId"}, + }, + { + name: "root_key_version_id", + update: func() *kms.TokenKeyVersion { + k := new.Clone().(*kms.TokenKeyVersion) + k.RootKeyVersionId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"RootKeyId"}, + }, + { + name: "version", + update: func() *kms.TokenKeyVersion { + k := new.Clone().(*kms.TokenKeyVersion) + k.Version = uint32(22) + return k + }(), + fieldMask: []string{"Version"}, + }, + { + name: "key", + update: func() *kms.TokenKeyVersion { + k := new.Clone().(*kms.TokenKeyVersion) + k.Key = []byte("updated key") + return k + }(), + fieldMask: []string{"CtKey"}, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + orig := new.Clone() + err := rw.LookupById(context.Background(), orig) + require.NoError(err) + + err = tt.update.Encrypt(context.Background(), wrapper) + require.NoError(err) + rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) + require.Error(err) + assert.Equal(0, rowsUpdated) + + after := new.Clone() + err = rw.LookupById(context.Background(), after) + require.NoError(err) + + assert.True(proto.Equal(orig.(*kms.TokenKeyVersion), after.(*kms.TokenKeyVersion))) + }) + } +} + +func TestSessionKey_ImmutableFields(t *testing.T) { + t.Parallel() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + + ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} + + wrapper := db.TestWrapper(t) + org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) + require.NoError(t, conn.Where("1=1").Delete(kms.AllocRootKey()).Error) + require.NoError(t, conn.Where("1=1").Delete(kms.AllocSessionKey()).Error) + rk := kms.TestRootKey(t, conn, org.PublicId) + new := kms.TestSessionKey(t, conn, rk.PrivateId) + + tests := []struct { + name string + update *kms.SessionKey + fieldMask []string + }{ + { + name: "private_id", + update: func() *kms.SessionKey { + k := new.Clone().(*kms.SessionKey) + k.PrivateId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"PrivateId"}, + }, + { + name: "create time", + update: func() *kms.SessionKey { + k := new.Clone().(*kms.SessionKey) + k.CreateTime = &ts + return k + }(), + fieldMask: []string{"CreateTime"}, + }, + { + name: "root_key_id", + update: func() *kms.SessionKey { + k := new.Clone().(*kms.SessionKey) + k.RootKeyId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"ScopeId"}, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + orig := new.Clone() + err := rw.LookupById(context.Background(), orig) + require.NoError(err) + + rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) + require.Error(err) + assert.Equal(0, rowsUpdated) + + after := new.Clone() + err = rw.LookupById(context.Background(), after) + require.NoError(err) + + assert.True(proto.Equal(orig.(*kms.SessionKey), after.(*kms.SessionKey))) + }) + } +} + +func TestSessionKeyVersion_ImmutableFields(t *testing.T) { + t.Parallel() + conn, _ := db.TestSetup(t, "postgres") + wrapper := db.TestWrapper(t) + rw := db.New(conn) + + ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} + + org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) + require.NoError(t, conn.Where("1=1").Delete(kms.AllocRootKey()).Error) + rk := kms.TestRootKey(t, conn, org.PublicId) + _, rkvWrapper := kms.TestRootKeyVersion(t, conn, wrapper, rk.PrivateId) + dk := kms.TestSessionKey(t, conn, rk.PrivateId) + new := kms.TestSessionKeyVersion(t, conn, rkvWrapper, dk.PrivateId, []byte("session key")) + + tests := []struct { + name string + update *kms.SessionKeyVersion + fieldMask []string + }{ + { + name: "private_id", + update: func() *kms.SessionKeyVersion { + k := new.Clone().(*kms.SessionKeyVersion) + k.PrivateId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"PrivateId"}, + }, + { + name: "create time", + update: func() *kms.SessionKeyVersion { + k := new.Clone().(*kms.SessionKeyVersion) + k.CreateTime = &ts + return k + }(), + fieldMask: []string{"CreateTime"}, + }, + { + name: "Session_key_id", + update: func() *kms.SessionKeyVersion { + k := new.Clone().(*kms.SessionKeyVersion) + k.SessionKeyId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"RootKeyId"}, + }, + { + name: "root_key_version_id", + update: func() *kms.SessionKeyVersion { + k := new.Clone().(*kms.SessionKeyVersion) + k.RootKeyVersionId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"RootKeyId"}, + }, + { + name: "version", + update: func() *kms.SessionKeyVersion { + k := new.Clone().(*kms.SessionKeyVersion) + k.Version = uint32(22) + return k + }(), + fieldMask: []string{"Version"}, + }, + { + name: "key", + update: func() *kms.SessionKeyVersion { + k := new.Clone().(*kms.SessionKeyVersion) + k.Key = []byte("updated key") + return k + }(), + fieldMask: []string{"CtKey"}, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + orig := new.Clone() + err := rw.LookupById(context.Background(), orig) + require.NoError(err) + + err = tt.update.Encrypt(context.Background(), wrapper) + require.NoError(err) + rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) + require.Error(err) + assert.Equal(0, rowsUpdated) + + after := new.Clone() + err = rw.LookupById(context.Background(), after) + require.NoError(err) + + assert.True(proto.Equal(orig.(*kms.SessionKeyVersion), after.(*kms.SessionKeyVersion))) + }) + } +} func TestRootKeyVersion_ImmutableFields(t *testing.T) { t.Parallel() @@ -341,6 +832,74 @@ func TestDatabaseKeyVersion_ImmutableFields(t *testing.T) { } } +func TestOidcKey_ImmutableFields(t *testing.T) { + t.Parallel() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + + ts := timestamp.Timestamp{Timestamp: ×tamppb.Timestamp{Seconds: 0, Nanos: 0}} + + wrapper := db.TestWrapper(t) + org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) + require.NoError(t, conn.Where("1=1").Delete(kms.AllocRootKey()).Error) + require.NoError(t, conn.Where("1=1").Delete(kms.AllocOidcKey()).Error) + rk := kms.TestRootKey(t, conn, org.PublicId) + new := kms.TestOidcKey(t, conn, rk.PrivateId) + + tests := []struct { + name string + update *kms.OidcKey + fieldMask []string + }{ + { + name: "private_id", + update: func() *kms.OidcKey { + k := new.Clone().(*kms.OidcKey) + k.PrivateId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"PrivateId"}, + }, + { + name: "create time", + update: func() *kms.OidcKey { + k := new.Clone().(*kms.OidcKey) + k.CreateTime = &ts + return k + }(), + fieldMask: []string{"CreateTime"}, + }, + { + name: "root_key_id", + update: func() *kms.OidcKey { + k := new.Clone().(*kms.OidcKey) + k.RootKeyId = "o_thisIsNotAValidId" + return k + }(), + fieldMask: []string{"ScopeId"}, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + orig := new.Clone() + err := rw.LookupById(context.Background(), orig) + require.NoError(err) + + rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) + require.Error(err) + assert.Equal(0, rowsUpdated) + + after := new.Clone() + err = rw.LookupById(context.Background(), after) + require.NoError(err) + + assert.True(proto.Equal(orig.(*kms.OidcKey), after.(*kms.OidcKey))) + }) + } +} + func TestOidcKeyVersion_ImmutableFields(t *testing.T) { t.Parallel() conn, _ := db.TestSetup(t, "postgres") diff --git a/internal/kms/repository_database_key.go b/internal/kms/repository_database_key.go index f9a27f405..94565b82c 100644 --- a/internal/kms/repository_database_key.go +++ b/internal/kms/repository_database_key.go @@ -110,7 +110,7 @@ func (r *Repository) LookupDatabaseKey(ctx context.Context, privateId string, _ // repository returning a count of the number of records deleted. All options // are ignored. func (r *Repository) DeleteDatabaseKey(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).LookupDatabaseKey" + const op = "kms.(Repository).DeleteDatabaseKey" if privateId == "" { return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") } diff --git a/internal/kms/repository_oidc_key.go b/internal/kms/repository_oidc_key.go index b43676ec5..892532401 100644 --- a/internal/kms/repository_oidc_key.go +++ b/internal/kms/repository_oidc_key.go @@ -110,7 +110,7 @@ func (r *Repository) LookupOidcKey(ctx context.Context, privateId string, _ ...O // repository returning a count of the number of records deleted. All options // are ignored. func (r *Repository) DeleteOidcKey(ctx context.Context, privateId string, _ ...Option) (int, error) { - const op = "kms.(Repository).LookupOidcKey" + const op = "kms.(Repository).DeleteOidcKey" if privateId == "" { return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing private id") } diff --git a/internal/kms/testing.go b/internal/kms/testing.go index 37ec6da7e..2eae274e2 100644 --- a/internal/kms/testing.go +++ b/internal/kms/testing.go @@ -220,7 +220,7 @@ func TestOidcKeyVersion(t *testing.T, conn *db.DB, rootKeyVersionWrapper wrappin require.NotEmpty(rootKeyVersionId) k, err := NewOidcKeyVersion(oidcKeyId, key, rootKeyVersionId) require.NoError(err) - id, err := newDatabaseKeyVersionId() + id, err := newOidcKeyVersionId() require.NoError(err) k.PrivateId = id err = k.Encrypt(context.Background(), rootKeyVersionWrapper) From 8ae6e9892fe340b4552c76878a5e4ec5dcfa45fc Mon Sep 17 00:00:00 2001 From: Jim Date: Thu, 28 Oct 2021 21:14:39 -0400 Subject: [PATCH 02/15] feature (events/audit): Add auth info to audit events (#1644) --- go.mod | 2 +- go.sum | 5 +- .../auth_method_service_taggable_test.go | 7 +- internal/observability/event/context_test.go | 2 +- internal/observability/event/event.go | 16 ++- internal/servers/controller/auth/auth.go | 66 +++++++-- internal/servers/controller/auth/auth_test.go | 128 ++++++++++++++++++ sdk/go.mod | 2 +- sdk/go.sum | 4 +- .../authmethods/auth_method_taggable_test.go | 3 +- 10 files changed, 205 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index d4889798c..2620e050d 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/hashicorp/dawdle v0.4.0 github.com/hashicorp/dbassert v0.0.0-20210708202608-ecf920cf1ed8 github.com/hashicorp/eventlogger v0.1.0 - github.com/hashicorp/eventlogger/filters/encrypt v0.1.5 + github.com/hashicorp/eventlogger/filters/encrypt v0.1.6-0.20211027211326-5db60a48f239 github.com/hashicorp/go-bexpr v0.1.10 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-hclog v0.16.2 diff --git a/go.sum b/go.sum index 7b149e68c..783ca4491 100644 --- a/go.sum +++ b/go.sum @@ -458,9 +458,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/eventlogger v0.1.0 h1:S6xc4gZVzewuDUP4R4Ngko419h/CGDuV/b4ADL3XLik= github.com/hashicorp/eventlogger v0.1.0/go.mod h1:a3IXf1aEJfpCPzseTOrwKj4fVW/Qn3oEmpQeaIznzH0= -github.com/hashicorp/eventlogger/filters/encrypt v0.1.5-0.20211025115820-78e1ded4aea1/go.mod h1:8rcez7Kw1zanB0/074qnOuGu7zxmNh9Xr2ZI+K4xVIA= -github.com/hashicorp/eventlogger/filters/encrypt v0.1.5 h1:kNkH4G6zzWlZSoI1I+B/ud4chVKTPL516C6jB7dRdlE= -github.com/hashicorp/eventlogger/filters/encrypt v0.1.5/go.mod h1:8rcez7Kw1zanB0/074qnOuGu7zxmNh9Xr2ZI+K4xVIA= +github.com/hashicorp/eventlogger/filters/encrypt v0.1.6-0.20211027211326-5db60a48f239 h1:Yh9tY0lige+y0trmjQeT9NRDo6+YvtNAzbmUNOsIUzI= +github.com/hashicorp/eventlogger/filters/encrypt v0.1.6-0.20211027211326-5db60a48f239/go.mod h1:8rcez7Kw1zanB0/074qnOuGu7zxmNh9Xr2ZI+K4xVIA= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= diff --git a/internal/gen/controller/api/services/auth_method_service_taggable_test.go b/internal/gen/controller/api/services/auth_method_service_taggable_test.go index 0dc6fb6b6..ad9176bcd 100644 --- a/internal/gen/controller/api/services/auth_method_service_taggable_test.go +++ b/internal/gen/controller/api/services/auth_method_service_taggable_test.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/boundary/sdk/pbs/controller/api" "github.com/hashicorp/boundary/sdk/wrapper" "github.com/hashicorp/eventlogger" + "github.com/hashicorp/eventlogger/filters/encrypt" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" structpb "google.golang.org/protobuf/types/known/structpb" @@ -81,7 +82,7 @@ func TestAuthenticate_Tags(t *testing.T) { "auth_url": structpb.NewStringValue("public-auth_url"), "token_id": structpb.NewStringValue("public-token_id"), "final_redirect_url": structpb.NewStringValue("public-final_redirect_url"), - "token": structpb.NewStringValue(""), + "token": structpb.NewStringValue(encrypt.RedactedData), }, }, }, @@ -121,8 +122,8 @@ func TestAuthenticate_Tags(t *testing.T) { "auth_url": structpb.NewStringValue("public-auth_url"), "token_id": structpb.NewStringValue("public-token_id"), "state": structpb.NewStringValue("public-state"), - "password": structpb.NewStringValue(""), - "code": structpb.NewStringValue(""), + "password": structpb.NewStringValue(encrypt.RedactedData), + "code": structpb.NewStringValue(encrypt.RedactedData), }, }, }, diff --git a/internal/observability/event/context_test.go b/internal/observability/event/context_test.go index f8a1c1555..67c402e38 100644 --- a/internal/observability/event/context_test.go +++ b/internal/observability/event/context_test.go @@ -662,7 +662,7 @@ func Test_WriteAudit(t *testing.T) { AuthAccountId: "test_auth_account_id", }, GrantsInfo: &event.GrantsInfo{ - Grants: []event.GrantsPair{ + Grants: []event.Grant{ { Grant: "test_grant", ScopeId: "test_grant_scope_id", diff --git a/internal/observability/event/event.go b/internal/observability/event/event.go index 53fb9ba8d..2de944ac8 100644 --- a/internal/observability/event/event.go +++ b/internal/observability/event/event.go @@ -25,20 +25,22 @@ type UserInfo struct { } type GrantsInfo struct { - Grants []GrantsPair `json:"grants_pair,omitempty"` + Grants []Grant `json:"grants,omitempty"` } -type GrantsPair struct { +type Grant struct { Grant string `json:"grant,omitempty" class:"public"` ScopeId string `json:"scope_id,omitempty" class:"public"` + RoleId string `json:"role_id,omitempty" class:"public"` } type Auth struct { - AuthTokenId string `json:"auth_token_id" class:"public"` - UserInfo *UserInfo `json:"user_info,omitempty"` // boundary field - GrantsInfo *GrantsInfo `json:"grants_info,omitempty"` - UserEmail string `json:"email,omitempty" class:"sensitive"` - UserName string `json:"name,omitempty" class:"sensitive"` + DisabledAuthEntirely *bool `json:"disabled_auth_entirely,omitempty" class:"public"` + AuthTokenId string `json:"auth_token_id" class:"public"` + UserInfo *UserInfo `json:"user_info,omitempty"` // boundary field + GrantsInfo *GrantsInfo `json:"grants_info,omitempty"` + UserEmail string `json:"email,omitempty" class:"sensitive"` + UserName string `json:"name,omitempty" class:"sensitive"` } type Request struct { diff --git a/internal/servers/controller/auth/auth.go b/internal/servers/controller/auth/auth.go index f39a76505..ebc6d23bb 100644 --- a/internal/servers/controller/auth/auth.go +++ b/internal/servers/controller/auth/auth.go @@ -140,6 +140,9 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) { v.ctx = ctx + ea := &event.Auth{} + defer event.WriteAudit(ctx, op, event.WithAuth(ea)) + opts := getOpts(opt...) ret.Scope = new(scopes.ScopeInfo) @@ -160,6 +163,8 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) { // In tests we often simply disable auth so we can test the service handlers // without fuss if v.requestInfo.DisableAuthEntirely { + yes := true + ea.DisabledAuthEntirely = &yes const op = "auth.(disabled).lookupScope" ret.Scope.Id = v.requestInfo.ScopeIdOverride if ret.Scope.Id == "" { @@ -205,6 +210,7 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) { if reqInfo != nil { reqInfo.UserId = ret.UserId } + ea.UserInfo = &event.UserInfo{UserId: ret.UserId} ret.Error = nil return } @@ -226,8 +232,10 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) { } var authResults perms.ACLResults + var grantTuples []perms.GrantTuple + var accountId, userName, userEmail string var err error - authResults, ret.UserId, ret.Scope, v.acl, err = v.performAuthCheck(ctx) + authResults, ret.UserId, accountId, userName, userEmail, ret.Scope, v.acl, grantTuples, err = v.performAuthCheck(ctx) if err != nil { event.WriteError(ctx, op, err, event.WithInfoMsg("error performing authn/authz check")) return @@ -262,10 +270,31 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) { if ret.UserId == AnonymousUserId { ret.Error = handlers.UnauthenticatedError() } + ea.UserInfo = &event.UserInfo{ + UserId: ret.UserId, + } return } } + grants := make([]event.Grant, 0, len(grantTuples)) + for _, g := range grantTuples { + grants = append(grants, event.Grant{ + Grant: g.Grant, + RoleId: g.RoleId, + ScopeId: g.ScopeId, + }) + } + ea.UserInfo = &event.UserInfo{ + UserId: ret.UserId, + AuthAccountId: accountId, + } + ea.GrantsInfo = &event.GrantsInfo{ + Grants: grants, + } + ea.UserName = userName + ea.UserEmail = userEmail + if reqInfo != nil { reqInfo.UserId = ret.UserId reqInfo.OutputFields = authResults.OutputFields @@ -401,15 +430,23 @@ func (v *verifier) decryptToken(ctx context.Context) { } } -func (v verifier) performAuthCheck(ctx context.Context) (aclResults perms.ACLResults, userId string, scopeInfo *scopes.ScopeInfo, retAcl perms.ACL, retErr error) { +func (v verifier) performAuthCheck(ctx context.Context) ( + aclResults perms.ACLResults, + userId string, + accountId string, + userName string, + userEmail string, + scopeInfo *scopes.ScopeInfo, + retAcl perms.ACL, + grantTuples []perms.GrantTuple, + retErr error) { const op = "auth.(verifier).performAuthCheck" // Ensure we return an error by default if we forget to set this somewhere - retErr = errors.NewDeprecated(errors.Unknown, op, "default auth error", errors.WithoutEvent()) + retErr = errors.New(ctx, errors.Unknown, op, "default auth error", errors.WithoutEvent()) // Make the linter happy _ = retErr scopeInfo = new(scopes.ScopeInfo) userId = AnonymousUserId - var accountId string // Validate the token and fetch the corresponding user ID switch v.requestInfo.TokenFormat { @@ -428,7 +465,7 @@ func (v verifier) performAuthCheck(ctx context.Context) (aclResults perms.ACLRes } tokenRepo, err := v.authTokenRepoFn() if err != nil { - retErr = errors.WrapDeprecated(err, op) + retErr = errors.Wrap(ctx, err, op) return } at, err := tokenRepo.ValidateToken(v.ctx, v.requestInfo.PublicId, v.requestInfo.Token) @@ -451,10 +488,18 @@ func (v verifier) performAuthCheck(ctx context.Context) (aclResults perms.ACLRes iamRepo, err := v.iamRepoFn() if err != nil { - retErr = errors.WrapDeprecated(err, op, errors.WithMsg("failed to get iam repo")) + retErr = errors.Wrap(ctx, err, op, errors.WithMsg("failed to get iam repo")) return } + u, _, err := iamRepo.LookupUser(ctx, userId) + if err != nil { + retErr = errors.Wrap(ctx, err, op, errors.WithMsg("failed to lookup user")) + return + } + userEmail = u.Email + userName = u.FullName + // Look up scope details to return. We can skip a lookup when using the // global scope switch v.res.ScopeId { @@ -470,11 +515,11 @@ func (v verifier) performAuthCheck(ctx context.Context) (aclResults perms.ACLRes default: scp, err := iamRepo.LookupScope(v.ctx, v.res.ScopeId) if err != nil { - retErr = errors.WrapDeprecated(err, op) + retErr = errors.Wrap(ctx, err, op) return } if scp == nil { - retErr = errors.NewDeprecated(errors.InvalidParameter, op, fmt.Sprint("non-existent scope $q", v.res.ScopeId)) + retErr = errors.New(ctx, errors.InvalidParameter, op, fmt.Sprint("non-existent scope $q", v.res.ScopeId)) return } scopeInfo = &scopes.ScopeInfo{ @@ -495,13 +540,12 @@ func (v verifier) performAuthCheck(ctx context.Context) (aclResults perms.ACLRes } var parsedGrants []perms.Grant - var grantTuples []perms.GrantTuple // Fetch and parse grants for this user ID (which may include grants for // u_anon and u_auth) grantTuples, err = iamRepo.GrantsForUser(v.ctx, userId) if err != nil { - retErr = errors.WrapDeprecated(err, op) + retErr = errors.Wrap(ctx, err, op) return } parsedGrants = make([]perms.Grant, 0, len(grantTuples)) @@ -516,7 +560,7 @@ func (v verifier) performAuthCheck(ctx context.Context) (aclResults perms.ACLRes perms.WithAccountId(accountId), perms.WithSkipFinalValidation(true)) if err != nil { - retErr = errors.WrapDeprecated(err, op, errors.WithMsg(fmt.Sprintf("failed to parse grant %#v", pair.Grant))) + retErr = errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed to parse grant %#v", pair.Grant))) return } parsedGrants = append(parsedGrants, parsed) diff --git a/internal/servers/controller/auth/auth_test.go b/internal/servers/controller/auth/auth_test.go index e90b523f2..0eda12218 100644 --- a/internal/servers/controller/auth/auth_test.go +++ b/internal/servers/controller/auth/auth_test.go @@ -5,6 +5,8 @@ import ( "fmt" "net/http" "net/http/httptest" + "os" + "sync" "testing" "github.com/hashicorp/boundary/internal/authtoken" @@ -12,8 +14,12 @@ import ( authpb "github.com/hashicorp/boundary/internal/gen/controller/auth" "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/kms" + "github.com/hashicorp/boundary/internal/observability/event" "github.com/hashicorp/boundary/internal/servers" "github.com/hashicorp/boundary/internal/servers/controller/handlers" + "github.com/hashicorp/boundary/internal/tests/api" + "github.com/hashicorp/eventlogger/filters/encrypt" + "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -132,3 +138,125 @@ func TestAuthTokenAuthenticator(t *testing.T) { }) } } + +func TestVerify_AuditEvent(t *testing.T) { + // this cannot run in parallel because it relies on envvar + // globals.BOUNDARY_DEVELOPER_ENABLE_EVENTS + event.TestEnableEventing(t, true) + eventConfig := event.TestEventerConfig(t, "Test_Verify", event.TestWithAuditSink(t)) + testLock := &sync.Mutex{} + testLogger := hclog.New(&hclog.LoggerOptions{ + Mutex: testLock, + Name: "test", + }) + require.NoError(t, event.InitSysEventer(testLogger, testLock, "Test_Verify", event.WithEventerConfig(&eventConfig.EventerConfig))) + + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrapper := db.TestWrapper(t) + testKms := kms.TestKms(t, conn, wrapper) + tokenRepo, err := authtoken.NewRepository(rw, rw, testKms) + require.NoError(t, err) + iamRepo := iam.TestRepo(t, conn, wrapper) + tokenRepoFn := func() (*authtoken.Repository, error) { + return tokenRepo, nil + } + iamRepoFn := func() (*iam.Repository, error) { + return iamRepo, nil + } + serversRepoFn := func() (*servers.Repository, error) { + return servers.NewRepository(rw, rw, testKms) + } + + o, _ := iam.TestScopes(t, iamRepo) + at := authtoken.TestAuthToken(t, conn, testKms, o.GetPublicId()) + encToken, err := authtoken.EncryptToken(context.Background(), testKms, o.GetPublicId(), at.GetPublicId(), at.GetToken()) + require.NoError(t, err) + + tokValue := at.GetPublicId() + "_" + encToken + jsCookieVal, httpCookieVal := tokValue[:len(tokValue)/2], tokValue[len(tokValue)/2:] + + tests := []struct { + name string + headers map[string]string + cookies []http.Cookie + opt []Option + disableAuth bool + wantResults VerifyResults + wantAuthAuditData bool + wantUserId string + }{ + { + name: "bearer-token", + headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", tokValue)}, + opt: []Option{WithScopeId(o.PublicId)}, + wantAuthAuditData: true, + wantUserId: at.IamUserId, + }, + { + name: "split-cookie-token", + cookies: []http.Cookie{ + {Name: handlers.HttpOnlyCookieName, Value: httpCookieVal}, + {Name: handlers.JsVisibleCookieName, Value: jsCookieVal}, + }, + opt: []Option{WithScopeId(o.PublicId)}, + wantAuthAuditData: true, + wantUserId: at.IamUserId, + }, + { + name: "no-auth-data", + opt: []Option{WithScopeId(o.PublicId)}, + wantAuthAuditData: true, + wantUserId: "u_anon", + }, + { + name: "disable-auth", + opt: []Option{WithScopeId(o.PublicId)}, + disableAuth: true, + wantAuthAuditData: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + req := httptest.NewRequest("GET", "http://127.0.0.1/v1/scopes/o_1", nil) + for k, v := range tt.headers { + req.Header.Set(k, v) + } + for _, c := range tt.cookies { + req.AddCookie(&c) + } + + // Add values for authn/authz checking + requestInfo := authpb.RequestInfo{ + Path: req.URL.Path, + Method: req.Method, + DisableAuthEntirely: tt.disableAuth, + } + requestInfo.PublicId, requestInfo.EncryptedToken, requestInfo.TokenFormat = GetTokenFromRequest(context.TODO(), testKms, req) + + ctx := NewVerifierContext(context.Background(), iamRepoFn, tokenRepoFn, serversRepoFn, testKms, &requestInfo) + + _ = os.WriteFile(eventConfig.AuditEvents.Name(), nil, 0o666) // clean out audit events from previous calls + _ = Verify(ctx, tt.opt...) + got := api.CloudEventFromFile(t, eventConfig.AuditEvents.Name()) + + if tt.wantAuthAuditData { + auth, ok := got.Data.(map[string]interface{})["auth"].(map[string]interface{}) + require.True(ok) + assert.Equal(encrypt.RedactedData, auth["email"]) + assert.Equal(encrypt.RedactedData, auth["name"]) + + if tt.disableAuth { + assert.Equal(true, auth["disabled_auth_entirely"]) + } + if tt.wantUserId != "" { + userInfo, ok := auth["user_info"].(map[string]interface{}) + require.True(ok) + assert.Equal(tt.wantUserId, userInfo["id"]) + } + } + }) + } +} diff --git a/sdk/go.mod b/sdk/go.mod index e4ec45cf9..90c808787 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -7,7 +7,7 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-cmp v0.5.6 // indirect github.com/hashicorp/eventlogger v0.1.0 - github.com/hashicorp/eventlogger/filters/encrypt v0.1.5 + github.com/hashicorp/eventlogger/filters/encrypt v0.1.6-0.20211027211326-5db60a48f239 github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-kms-wrapping v0.6.6 github.com/hashicorp/go-retryablehttp v0.7.0 // indirect diff --git a/sdk/go.sum b/sdk/go.sum index ce2eba262..146017010 100644 --- a/sdk/go.sum +++ b/sdk/go.sum @@ -237,8 +237,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/eventlogger v0.1.0 h1:S6xc4gZVzewuDUP4R4Ngko419h/CGDuV/b4ADL3XLik= github.com/hashicorp/eventlogger v0.1.0/go.mod h1:a3IXf1aEJfpCPzseTOrwKj4fVW/Qn3oEmpQeaIznzH0= -github.com/hashicorp/eventlogger/filters/encrypt v0.1.5 h1:kNkH4G6zzWlZSoI1I+B/ud4chVKTPL516C6jB7dRdlE= -github.com/hashicorp/eventlogger/filters/encrypt v0.1.5/go.mod h1:8rcez7Kw1zanB0/074qnOuGu7zxmNh9Xr2ZI+K4xVIA= +github.com/hashicorp/eventlogger/filters/encrypt v0.1.6-0.20211027211326-5db60a48f239 h1:Yh9tY0lige+y0trmjQeT9NRDo6+YvtNAzbmUNOsIUzI= +github.com/hashicorp/eventlogger/filters/encrypt v0.1.6-0.20211027211326-5db60a48f239/go.mod h1:8rcez7Kw1zanB0/074qnOuGu7zxmNh9Xr2ZI+K4xVIA= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= diff --git a/sdk/pbs/controller/api/resources/authmethods/auth_method_taggable_test.go b/sdk/pbs/controller/api/resources/authmethods/auth_method_taggable_test.go index a4018792a..aab9f930d 100644 --- a/sdk/pbs/controller/api/resources/authmethods/auth_method_taggable_test.go +++ b/sdk/pbs/controller/api/resources/authmethods/auth_method_taggable_test.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/boundary/sdk/pbs/controller/api" "github.com/hashicorp/boundary/sdk/wrapper" "github.com/hashicorp/eventlogger" + "github.com/hashicorp/eventlogger/filters/encrypt" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/structpb" @@ -92,7 +93,7 @@ func TestAuthMethod_Tags(t *testing.T) { "account_claim_maps": structpb.NewStringValue("public-account_claim_maps"), "disable_discovered_config_validation": structpb.NewStringValue("public-disable_discovered_config_validation"), "dry_run": structpb.NewStringValue("public-dry_run"), - "client_secret": structpb.NewStringValue(""), + "client_secret": structpb.NewStringValue(encrypt.RedactedData), }, }, AuthorizedActions: []string{"action-1", "action-2"}, From 2cc58ff9014deb3cf48d1d2fe158467978ff2a0e Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Tue, 26 Oct 2021 09:57:22 -0400 Subject: [PATCH 03/15] refact(target): Change repository to take CredentialLibraries This change removes the hard-coded credential purpose for the Credential Libraries. It also moves the logic of creating CredentialLibraries from CredentialSources out of the repository and into the targets.Service. This refactor will allow for additional credential purposes to be supported in both the service and the repository. --- Makefile | 1 + internal/credential/credential.go | 11 + .../migrations/oss/postgres_16_05_test.go | 15 +- .../target/targettest/store/v1/target.proto | 73 +++++ .../handlers/targets/target_service.go | 48 ++- .../handlers/targets/target_service_test.go | 33 +- internal/session/repository_session_test.go | 23 +- internal/target/credential_library.go | 4 +- internal/target/credential_library_test.go | 2 +- internal/target/options.go | 10 +- internal/target/options_test.go | 34 +- internal/target/query.go | 3 +- .../target/repository_credential_source.go | 119 ++++--- .../repository_credential_source_test.go | 254 +++++++++++++++ internal/target/targettest/store/target.pb.go | 307 ++++++++++++++++++ internal/target/targettest/target.go | 262 +++++++++++++++ .../tcp/repository_credential_source_test.go | 88 +++-- .../target/tcp/repository_tcp_target_test.go | 26 +- internal/target/tcp/testing.go | 11 +- internal/target/testing.go | 22 +- 20 files changed, 1213 insertions(+), 133 deletions(-) create mode 100644 internal/proto/local/controller/storage/target/targettest/store/v1/target.proto create mode 100644 internal/target/repository_credential_source_test.go create mode 100644 internal/target/targettest/store/target.pb.go create mode 100644 internal/target/targettest/target.go diff --git a/Makefile b/Makefile index 51296c11e..41aef097c 100644 --- a/Makefile +++ b/Makefile @@ -129,6 +129,7 @@ protobuild: @protoc-go-inject-tag -input=./internal/kms/store/session_key.pb.go @protoc-go-inject-tag -input=./internal/kms/store/oidc_key.pb.go @protoc-go-inject-tag -input=./internal/target/store/target.pb.go + @protoc-go-inject-tag -input=./internal/target/targettest/store/target.pb.go @protoc-go-inject-tag -input=./internal/target/tcp/store/target.pb.go @protoc-go-inject-tag -input=./internal/auth/oidc/store/oidc.pb.go @protoc-go-inject-tag -input=./internal/scheduler/job/store/job.pb.go diff --git a/internal/credential/credential.go b/internal/credential/credential.go index 98b311637..5c337ae21 100644 --- a/internal/credential/credential.go +++ b/internal/credential/credential.go @@ -28,6 +28,10 @@ type Library interface { // Purpose is the purpose of the credential. type Purpose string +func (p Purpose) String() string { + return string(p) +} + // Credential purpose values. const ( // ApplicationPurpose is a credential used for application specific @@ -45,6 +49,13 @@ const ( EgressPurpose Purpose = "egress" ) +// ValidPurposes are the set of all credential Purposes. +var ValidPurposes = []Purpose{ + ApplicationPurpose, + IngressPurpose, + EgressPurpose, +} + // SecretData represents secret data. type SecretData interface{} diff --git a/internal/db/schema/migrations/oss/postgres_16_05_test.go b/internal/db/schema/migrations/oss/postgres_16_05_test.go index d2c279751..b63444085 100644 --- a/internal/db/schema/migrations/oss/postgres_16_05_test.go +++ b/internal/db/schema/migrations/oss/postgres_16_05_test.go @@ -165,16 +165,21 @@ func testSessionCredentialParams(t *testing.T, conn *db.DB, kms *kms.Kms, wrappe ctx := context.Background() stores := vault.TestCredentialStores(t, conn, wrapper, tar.GetScopeId(), 1) - libs := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2) + libIds := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2) + libs := []*target.CredentialLibrary{ + target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.ApplicationPurpose), + target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.IngressPurpose), + target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), credential.EgressPurpose), + } targetRepo, err := target.NewRepository(rw, rw, kms) require.NoError(t, err) - _, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tar.GetPublicId(), tar.GetVersion(), []string{libs[0].PublicId, libs[1].PublicId}) + _, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tar.GetPublicId(), tar.GetVersion(), libs) require.NoError(t, err) creds := []*session.DynamicCredential{ - session.NewDynamicCredential(libs[0].GetPublicId(), credential.ApplicationPurpose), - session.NewDynamicCredential(libs[0].GetPublicId(), credential.IngressPurpose), - session.NewDynamicCredential(libs[1].GetPublicId(), credential.EgressPurpose), + session.NewDynamicCredential(libIds[0].GetPublicId(), credential.ApplicationPurpose), + session.NewDynamicCredential(libIds[0].GetPublicId(), credential.IngressPurpose), + session.NewDynamicCredential(libIds[1].GetPublicId(), credential.EgressPurpose), } return creds } diff --git a/internal/proto/local/controller/storage/target/targettest/store/v1/target.proto b/internal/proto/local/controller/storage/target/targettest/store/v1/target.proto new file mode 100644 index 000000000..b9471c819 --- /dev/null +++ b/internal/proto/local/controller/storage/target/targettest/store/v1/target.proto @@ -0,0 +1,73 @@ +syntax = "proto3"; + +package controller.storage.target.targettest.store.v1; +option go_package = "github.com/hashicorp/boundary/internal/target/targettest/store;store"; + +import "controller/storage/timestamp/v1/timestamp.proto"; +import "controller/custom_options/v1/options.proto"; + +message Target { + // public_id is used to access the targettest.Target via an API + // @inject_tag: gorm:"primary_key" + string public_id = 10; + + // scope id for the targettest.Target + // @inject_tag: `gorm:"default:null"` + string scope_id = 20; + + // name is the optional friendly name used to + // access the targettest.Target via an API + // @inject_tag: `gorm:"default:null"` + string name = 30 + [(custom_options.v1.mask_mapping) = { this: "name" that: "name" }]; + + // description of the targettest.Target + // @inject_tag: `gorm:"default:null"` + string description = 40 [(custom_options.v1.mask_mapping) = { + this: "description" + that: "description" + }]; + + // create_time from the RDBMS + // @inject_tag: `gorm:"default:current_timestamp"` + timestamp.v1.Timestamp create_time = 50; + + // update_time from the RDBMS + // @inject_tag: `gorm:"default:current_timestamp"` + timestamp.v1.Timestamp update_time = 60; + + // version allows optimistic locking of the targettest.Target when modifying the + // targettest.Target + // @inject_tag: `gorm:"default:null"` + uint32 version = 70; + + // default port of the targettest.Target + // @inject_tag: `gorm:"default:null"` + uint32 default_port = 80 [(custom_options.v1.mask_mapping) = { + this: "DefaultPort" + that: "attributes.default_port" + }]; + + // Maximum total lifetime of a created session, in seconds + // @inject_tag: `gorm:"default:null"` + uint32 session_max_seconds = 100 [(custom_options.v1.mask_mapping) = { + this: "SessionMaxSeconds" + that: "session_max_seconds" + }]; + + // Maximum number of connections in a session + // @inject_tag: `gorm:"default:null"` + int32 session_connection_limit = 110 [(custom_options.v1.mask_mapping) = { + this: "SessionConnectionLimit" + that: "session_connection_limit" + }]; + + // A boolean expression that allows filtering the workers that can handle a session + // @inject_tag: `gorm:"default:null"` + string worker_filter = 120 [(custom_options.v1.mask_mapping) = { + this: "WorkerFilter" + that: "worker_filter" + }]; +} + + diff --git a/internal/servers/controller/handlers/targets/target_service.go b/internal/servers/controller/handlers/targets/target_service.go index 78c1261de..4c9f9eb1b 100644 --- a/internal/servers/controller/handlers/targets/target_service.go +++ b/internal/servers/controller/handlers/targets/target_service.go @@ -1346,12 +1346,17 @@ func (s Service) removeHostSourcesInRepo(ctx context.Context, targetId string, h return out, hs, cl, nil } -func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string, ids []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) { +func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) { repo, err := s.repoFn() if err != nil { return nil, nil, nil, err } - out, hs, credSources, err := repo.AddTargetCredentialSources(ctx, targetId, version, strutil.RemoveDuplicates(ids, false)) + credLibs, err := createCredLibs(targetId, applicationIds, nil, nil) + if err != nil { + return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err) + } + + out, hs, credSources, err := repo.AddTargetCredentialSources(ctx, targetId, version, credLibs) if err != nil { // TODO: Figure out a way to surface more helpful error info beyond the Internal error. return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to add credential sources to target: %v.", err) @@ -1362,13 +1367,19 @@ func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string return out, hs, credSources, nil } -func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string, ids []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) { +func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) { const op = "targets.(Service).setCredentialSourcesInRepo" repo, err := s.repoFn() if err != nil { return nil, nil, nil, err } - _, _, _, err = repo.SetTargetCredentialSources(ctx, targetId, version, strutil.RemoveDuplicates(ids, false)) + + credLibs, err := createCredLibs(targetId, applicationIds, nil, nil) + if err != nil { + return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err) + } + + _, _, _, err = repo.SetTargetCredentialSources(ctx, targetId, version, credLibs) if err != nil { // TODO: Figure out a way to surface more helpful error info beyond the Internal error. return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err) @@ -1384,13 +1395,18 @@ func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string return out, hs, credSources, nil } -func (s Service) removeCredentialSourcesInRepo(ctx context.Context, targetId string, ids []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) { +func (s Service) removeCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) { const op = "targets.(Service).removeCredentialSourcesInRepo" repo, err := s.repoFn() if err != nil { return nil, nil, nil, err } - _, err = repo.DeleteTargetCredentialSources(ctx, targetId, version, strutil.RemoveDuplicates(ids, false)) + + credLibs, err := createCredLibs(targetId, applicationIds, nil, nil) + if err != nil { + return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err) + } + _, err = repo.DeleteTargetCredentialSources(ctx, targetId, version, credLibs) if err != nil { // TODO: Figure out a way to surface more helpful error info beyond the Internal error. return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to remove credential sources from target: %v.", err) @@ -2003,3 +2019,23 @@ func validateAuthorizeSessionRequest(req *pbs.AuthorizeSessionRequest) error { } return nil } + +func createCredLibs(targetId string, applicationIds, ingressIds, egressIds []string) ([]*target.CredentialLibrary, error) { + credLibs := make([]*target.CredentialLibrary, 0, len(applicationIds)+len(ingressIds)+len(egressIds)) + + byPurpose := map[credential.Purpose][]string{ + credential.ApplicationPurpose: strutil.RemoveDuplicates(applicationIds, false), + credential.IngressPurpose: strutil.RemoveDuplicates(ingressIds, false), + credential.EgressPurpose: strutil.RemoveDuplicates(egressIds, false), + } + for purpose, ids := range byPurpose { + for _, id := range ids { + l, err := target.NewCredentialLibrary(targetId, id, purpose) + if err != nil { + return nil, err + } + credLibs = append(credLibs, l) + } + } + return credLibs, nil +} diff --git a/internal/servers/controller/handlers/targets/target_service_test.go b/internal/servers/controller/handlers/targets/target_service_test.go index 700ad493b..8c77191df 100644 --- a/internal/servers/controller/handlers/targets/target_service_test.go +++ b/internal/servers/controller/handlers/targets/target_service_test.go @@ -14,6 +14,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/boundary/internal/authtoken" + "github.com/hashicorp/boundary/internal/credential" "github.com/hashicorp/boundary/internal/credential/vault" "github.com/hashicorp/boundary/internal/db" pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services" @@ -1704,13 +1705,13 @@ func TestAddTargetLibraries(t *testing.T) { }, { name: "Add library on populated target", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for libraries", target.WithCredentialSources([]string{cls[0].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for libraries", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})), addLibraries: []string{cls[1].GetPublicId()}, resultLibraryIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()}, }, { name: "Add duplicated libraries on populated target", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for libraries", target.WithCredentialSources([]string{cls[0].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for libraries", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})), addLibraries: []string{cls[1].GetPublicId(), cls[1].GetPublicId()}, resultLibraryIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()}, }, @@ -1840,19 +1841,19 @@ func TestSetTargetLibraries(t *testing.T) { }, { name: "Set on populated target", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})), setLibraries: []string{cls[1].GetPublicId()}, resultLibraryIds: []string{cls[1].GetPublicId()}, }, { name: "Set duplicate libraries on populated target", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})), setLibraries: []string{cls[1].GetPublicId(), cls[1].GetPublicId()}, resultLibraryIds: []string{cls[1].GetPublicId()}, }, { name: "Set empty on populated target", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})), setLibraries: []string{}, resultLibraryIds: nil, }, @@ -1966,13 +1967,13 @@ func TestRemoveTargetLibraries(t *testing.T) { }, { name: "Remove 1 of 2 libraries", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})), removeLibs: []string{cls[1].GetPublicId()}, resultLibIds: []string{cls[0].GetPublicId()}, }, { name: "Remove 1 duplicate set of 2 libraries", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})), removeLibs: []string{ cls[1].GetPublicId(), cls[1].GetPublicId(), }, @@ -1980,7 +1981,7 @@ func TestRemoveTargetLibraries(t *testing.T) { }, { name: "Remove all libraries from target", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})), removeLibs: []string{ cls[0].GetPublicId(), cls[1].GetPublicId(), }, @@ -2101,13 +2102,13 @@ func TestAddTargetSources(t *testing.T) { }, { name: "Add source on populated target", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for sources", target.WithCredentialSources([]string{cls[0].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})), addSources: []string{cls[1].GetPublicId()}, resultSourceIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()}, }, { name: "Add duplicated sources on populated target", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for sources", target.WithCredentialSources([]string{cls[0].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})), addSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId()}, resultSourceIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()}, }, @@ -2237,19 +2238,19 @@ func TestSetTargetCredentialSources(t *testing.T) { }, { name: "Set on populated target", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})), setCredentialSources: []string{cls[1].GetPublicId()}, resultCredentialSourceIds: []string{cls[1].GetPublicId()}, }, { name: "Set duplicate sources on populated target", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})), setCredentialSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId()}, resultCredentialSourceIds: []string{cls[1].GetPublicId()}, }, { name: "Set empty on populated target", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})), setCredentialSources: []string{}, resultCredentialSourceIds: nil, }, @@ -2363,13 +2364,13 @@ func TestRemoveTargetCredentialSources(t *testing.T) { }, { name: "Remove 1 of 2 sources", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})), removeCredentialSources: []string{cls[1].GetPublicId()}, resultCredentialSourceIds: []string{cls[0].GetPublicId()}, }, { name: "Remove 1 duplicate set of 2 sources", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})), removeCredentialSources: []string{ cls[1].GetPublicId(), cls[1].GetPublicId(), }, @@ -2377,7 +2378,7 @@ func TestRemoveTargetCredentialSources(t *testing.T) { }, { name: "Remove all sources from target", - tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})), + tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})), removeCredentialSources: []string{ cls[0].GetPublicId(), cls[1].GetPublicId(), }, diff --git a/internal/session/repository_session_test.go b/internal/session/repository_session_test.go index 68e9076f1..f2107a71d 100644 --- a/internal/session/repository_session_test.go +++ b/internal/session/repository_session_test.go @@ -1649,21 +1649,28 @@ func testSessionCredentialParams(t *testing.T, conn *db.DB, wrapper wrapping.Wra rw := db.New(conn) ctx := context.Background() - stores := vault.TestCredentialStores(t, conn, wrapper, params.ScopeId, 1) - libs := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2) kms := kms.TestKms(t, conn, wrapper) targetRepo, err := target.NewRepository(rw, rw, kms) require.NoError(err) - tcpTarget, _, _, err := targetRepo.LookupTarget(ctx, params.TargetId) + tar, _, _, err := targetRepo.LookupTarget(ctx, params.TargetId) require.NoError(err) - require.NotNil(tcpTarget) - _, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tcpTarget.GetPublicId(), tcpTarget.GetVersion(), []string{libs[0].PublicId, libs[1].PublicId}) + require.NotNil(tar) + + stores := vault.TestCredentialStores(t, conn, wrapper, params.ScopeId, 1) + libIds := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2) + libs := []*target.CredentialLibrary{ + target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.ApplicationPurpose), + target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.IngressPurpose), + target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), credential.EgressPurpose), + } + + _, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tar.GetPublicId(), tar.GetVersion(), libs) require.NoError(err) creds := []*DynamicCredential{ - NewDynamicCredential(libs[0].GetPublicId(), credential.ApplicationPurpose), - NewDynamicCredential(libs[0].GetPublicId(), credential.IngressPurpose), - NewDynamicCredential(libs[1].GetPublicId(), credential.EgressPurpose), + NewDynamicCredential(libIds[0].GetPublicId(), credential.ApplicationPurpose), + NewDynamicCredential(libIds[0].GetPublicId(), credential.IngressPurpose), + NewDynamicCredential(libIds[1].GetPublicId(), credential.EgressPurpose), } params.DynamicCredentials = creds return params diff --git a/internal/target/credential_library.go b/internal/target/credential_library.go index 97d83f811..8c013a4d8 100644 --- a/internal/target/credential_library.go +++ b/internal/target/credential_library.go @@ -21,7 +21,7 @@ type CredentialLibrary struct { // NewCredentialLibrary creates a new in memory CredentialLibrary // representing the relationship between targetId and credentialLibraryId. -func NewCredentialLibrary(targetId, credentialLibraryId string, _ ...Option) (*CredentialLibrary, error) { +func NewCredentialLibrary(targetId, credentialLibraryId string, purpose credential.Purpose) (*CredentialLibrary, error) { const op = "target.NewCredentialLibrary" if targetId == "" { return nil, errors.NewDeprecated(errors.InvalidParameter, op, "no target id") @@ -34,7 +34,7 @@ func NewCredentialLibrary(targetId, credentialLibraryId string, _ ...Option) (*C CredentialLibrary: &store.CredentialLibrary{ TargetId: targetId, CredentialLibraryId: credentialLibraryId, - CredentialPurpose: string(credential.ApplicationPurpose), // application is the only purpose currently supported + CredentialPurpose: string(purpose), }, } return t, nil diff --git a/internal/target/credential_library_test.go b/internal/target/credential_library_test.go index a079f471b..fb36b27f9 100644 --- a/internal/target/credential_library_test.go +++ b/internal/target/credential_library_test.go @@ -55,7 +55,7 @@ func TestCredentialLibrary_New(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { assert, require := assert.New(t), require.New(t) - got, err := target.NewCredentialLibrary(tt.args.targetId, tt.args.libraryId) + got, err := target.NewCredentialLibrary(tt.args.targetId, tt.args.libraryId, credential.ApplicationPurpose) if tt.wantErr != 0 { assert.Truef(errors.Match(errors.T(tt.wantErr), err), "want err: %q got: %q", tt.wantErr, err) assert.Nil(got) diff --git a/internal/target/options.go b/internal/target/options.go index 5fa1bbe08..69565cd3c 100644 --- a/internal/target/options.go +++ b/internal/target/options.go @@ -30,7 +30,7 @@ type options struct { WithUserId string WithType subtypes.Subtype WithHostSources []string - WithCredentialSources []string + WithCredentialLibraries []*CredentialLibrary WithSessionMaxSeconds uint32 WithSessionConnectionLimit int32 WithPublicId string @@ -49,7 +49,7 @@ func getDefaultOptions() options { WithUserId: "", WithType: "", WithHostSources: nil, - WithCredentialSources: nil, + WithCredentialLibraries: nil, WithSessionMaxSeconds: uint32((8 * time.Hour).Seconds()), WithSessionConnectionLimit: 1, WithPublicId: "", @@ -129,10 +129,10 @@ func WithHostSources(hs []string) Option { } } -// WithCredentialSources provides an option for providing a list of credential source ids -func WithCredentialSources(cl []string) Option { +// WithCredentialLibraries provides an option for providing a list of credential libraries. +func WithCredentialLibraries(cl []*CredentialLibrary) Option { return func(o *options) { - o.WithCredentialSources = cl + o.WithCredentialLibraries = cl } } diff --git a/internal/target/options_test.go b/internal/target/options_test.go index a4d3431f5..0746102d6 100644 --- a/internal/target/options_test.go +++ b/internal/target/options_test.go @@ -3,6 +3,8 @@ package target import ( "testing" + "github.com/hashicorp/boundary/internal/credential" + "github.com/hashicorp/boundary/internal/target/store" "github.com/hashicorp/boundary/internal/types/subtypes" "github.com/stretchr/testify/assert" ) @@ -106,11 +108,37 @@ func Test_GetOpts(t *testing.T) { testOpts.WithWorkerFilter = `"/foo" == "bar"` assert.Equal(opts, testOpts) }) - t.Run("WithCredentialSources", func(t *testing.T) { + t.Run("WithCredentialLibraries", func(t *testing.T) { assert := assert.New(t) - opts := GetOpts(WithCredentialSources([]string{"alice", "bob"})) + opts := GetOpts(WithCredentialLibraries([]*CredentialLibrary{ + { + CredentialLibrary: &store.CredentialLibrary{ + CredentialLibraryId: "alice", + CredentialPurpose: string(credential.ApplicationPurpose), + }, + }, + { + CredentialLibrary: &store.CredentialLibrary{ + CredentialLibraryId: "bob", + CredentialPurpose: string(credential.EgressPurpose), + }, + }, + })) testOpts := getDefaultOptions() - testOpts.WithCredentialSources = []string{"alice", "bob"} + testOpts.WithCredentialLibraries = []*CredentialLibrary{ + { + CredentialLibrary: &store.CredentialLibrary{ + CredentialLibraryId: "alice", + CredentialPurpose: string(credential.ApplicationPurpose), + }, + }, + { + CredentialLibrary: &store.CredentialLibrary{ + CredentialLibraryId: "bob", + CredentialPurpose: string(credential.EgressPurpose), + }, + }, + } assert.Equal(opts, testOpts) }) } diff --git a/internal/target/query.go b/internal/target/query.go index 7dc5c09a4..054861eee 100644 --- a/internal/target/query.go +++ b/internal/target/query.go @@ -13,7 +13,8 @@ current_libraries (library_id) as ( -- returns the current list select credential_library_id from target_credential_library - where target_id = @target_id + where target_id = @target_id + and credential_purpose = @purpose ), keep_libraries (library_id) as ( -- returns the KEEP list diff --git a/internal/target/repository_credential_source.go b/internal/target/repository_credential_source.go index 31284bf1e..2cad2a345 100644 --- a/internal/target/repository_credential_source.go +++ b/internal/target/repository_credential_source.go @@ -6,17 +6,46 @@ import ( "fmt" "strings" + "github.com/hashicorp/boundary/internal/credential" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/oplog" + "github.com/hashicorp/boundary/internal/target/store" ) +// credentialLibrariesPurposeMap is used to group CredentialLibraries by purpose. +type credentialLibrariesPurposeMap map[string][]*CredentialLibrary + +func (c credentialLibrariesPurposeMap) add(cl *CredentialLibrary) { + var s []*CredentialLibrary + var ok bool + + s, ok = c[cl.CredentialPurpose] + if !ok { + s = make([]*CredentialLibrary, 0, 1) + } + + s = append(s, cl) + c[cl.CredentialPurpose] = s +} + +func newCredentialLibrariesPurposeMap(cls []*CredentialLibrary) credentialLibrariesPurposeMap { + clpm := make(credentialLibrariesPurposeMap) + for _, p := range credential.ValidPurposes { + clpm[p.String()] = make([]*CredentialLibrary, 0) + } + for _, cl := range cls { + clpm.add(cl) + } + return clpm +} + // AddTargetCredentialSources adds the cIds to the targetId in the repository. The target // and the list of credential sources attached to the target, after cIds are added, // will be returned on success. // The targetVersion must match the current version of the targetId in the repository. -func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, cIds []string, _ ...Option) (Target, []HostSource, []CredentialSource, error) { +func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, cls []*CredentialLibrary, _ ...Option) (Target, []HostSource, []CredentialSource, error) { const op = "target.(Repository).AddTargetCredentialSources" if targetId == "" { return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing target id") @@ -24,16 +53,12 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st if targetVersion == 0 { return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing version") } - if len(cIds) == 0 { - return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing credential source ids") + if len(cls) == 0 { + return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing credential libraries") } - addCredLibs := make([]interface{}, 0, len(cIds)) - for _, id := range cIds { - cl, err := NewCredentialLibrary(targetId, id) - if err != nil { - return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory credential library")) - } + addCredLibs := make([]interface{}, 0, len(cls)) + for _, cl := range cls { addCredLibs = append(addCredLibs, cl) } @@ -115,7 +140,7 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st // DeleteTargetCredentialSources deletes credential sources from a target in the repository. // The target's current db version must match the targetVersion or an error will be returned. -func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, csIds []string, _ ...Option) (int, error) { +func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, cls []*CredentialLibrary, _ ...Option) (int, error) { const op = "target.(Repository).DeleteTargetCredentialSources" if targetId == "" { return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target id") @@ -123,16 +148,12 @@ func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId if targetVersion == 0 { return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing version") } - if len(csIds) == 0 { + if len(cls) == 0 { return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing credential source ids") } - deleteCredLibs := make([]interface{}, 0, len(csIds)) - for _, id := range csIds { - cl, err := NewCredentialLibrary(targetId, id) - if err != nil { - return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory credential library")) - } + deleteCredLibs := make([]interface{}, 0, len(cls)) + for _, cl := range cls { deleteCredLibs = append(deleteCredLibs, cl) } @@ -208,7 +229,7 @@ func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId // SetTargetCredentialSources will set the target's credential sources. Set will add // and/or delete credential sources as need to reconcile the existing credential sources // with the request. If clIds is empty, all the credential sources will be cleared from the target. -func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, csIds []string, _ ...Option) ([]HostSource, []CredentialSource, int, error) { +func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, cls []*CredentialLibrary, _ ...Option) ([]HostSource, []CredentialSource, int, error) { const op = "target.(Repository).SetTargetCredentialSources" if targetId == "" { return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target id") @@ -217,10 +238,18 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing version") } - changes, err := r.changes(ctx, targetId, csIds) - if err != nil { - return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op) + clpm := newCredentialLibrariesPurposeMap(cls) + + var changes []*change + + for purpose, cls := range clpm { + c, err := r.changes(ctx, targetId, cls, purpose) + if err != nil { + return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op) + } + changes = append(changes, c...) } + if len(changes) == 0 { // Nothing needs to be changed, return early hostSets, err := fetchHostSources(ctx, r.reader, targetId) @@ -236,15 +265,11 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st var deleteCredLibs, addCredLibs []interface{} for _, c := range changes { - cl, err := NewCredentialLibrary(targetId, c.LibraryId) - if err != nil { - return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory target credential library")) - } - switch c.Action { + switch c.action { case "delete": - deleteCredLibs = append(deleteCredLibs, cl) + deleteCredLibs = append(deleteCredLibs, c.credentialLibrary) case "add": - addCredLibs = append(addCredLibs, cl) + addCredLibs = append(addCredLibs, c.credentialLibrary) } } @@ -343,28 +368,33 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st } type change struct { + action string + credentialLibrary *CredentialLibrary +} + +type changeQueryResult struct { Action string LibraryId string } -func (r *Repository) changes(ctx context.Context, targetId string, clIds []string) ([]*change, error) { +func (r *Repository) changes(ctx context.Context, targetId string, cls []*CredentialLibrary, purpose string) ([]*change, error) { const op = "target.(Repository).changes" + + // TODO ensure that all cls have the same purpose as the given purpose? + var inClauseSpots []string - // starts at 2 because there is already a @1 in the query - for i := 2; i < len(clIds)+2; i++ { - inClauseSpots = append(inClauseSpots, fmt.Sprintf("@%d", i)) + var params []interface{} + params = append(params, sql.Named("target_id", targetId), sql.Named("purpose", purpose)) + for idx, cl := range cls { + params = append(params, sql.Named(fmt.Sprintf("%d", idx+1), cl.CredentialLibraryId)) + inClauseSpots = append(inClauseSpots, fmt.Sprintf("@%d", idx+1)) } inClause := strings.Join(inClauseSpots, ",") if inClause == "" { inClause = "''" } - query := fmt.Sprintf(setChangesQuery, inClause) - var params []interface{} - params = append(params, sql.Named("target_id", targetId)) - for idx, id := range clIds { - params = append(params, sql.Named(fmt.Sprintf("%d", idx+2), id)) - } + query := fmt.Sprintf(setChangesQuery, inClause) rows, err := r.reader.Query(ctx, query, params) if err != nil { return nil, errors.Wrap(ctx, err, op, errors.WithMsg("query failed")) @@ -373,11 +403,20 @@ func (r *Repository) changes(ctx context.Context, targetId string, clIds []strin var changes []*change for rows.Next() { - var chg change + var chg changeQueryResult if err := r.reader.ScanRows(rows, &chg); err != nil { return nil, errors.Wrap(ctx, err, op, errors.WithMsg("scan row failed")) } - changes = append(changes, &chg) + changes = append(changes, &change{ + action: chg.Action, + credentialLibrary: &CredentialLibrary{ + CredentialLibrary: &store.CredentialLibrary{ + TargetId: targetId, + CredentialLibraryId: chg.LibraryId, + CredentialPurpose: purpose, + }, + }, + }) } return changes, nil } diff --git a/internal/target/repository_credential_source_test.go b/internal/target/repository_credential_source_test.go new file mode 100644 index 000000000..46cf8985c --- /dev/null +++ b/internal/target/repository_credential_source_test.go @@ -0,0 +1,254 @@ +package target_test + +import ( + "context" + "testing" + + "github.com/hashicorp/boundary/internal/credential" + "github.com/hashicorp/boundary/internal/credential/vault" + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/errors" + "github.com/hashicorp/boundary/internal/iam" + "github.com/hashicorp/boundary/internal/kms" + "github.com/hashicorp/boundary/internal/target" + "github.com/hashicorp/boundary/internal/target/targettest" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRepository_SetTargetCredentialSources(t *testing.T) { + target.Register(targettest.Subtype, targettest.Alloc, targettest.Vet, targettest.TargetPrefix) + + t.Parallel() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrapper := db.TestWrapper(t) + testKms := kms.TestKms(t, conn, wrapper) + repo, err := target.NewRepository(rw, rw, testKms) + require.NoError(t, err) + + iamRepo := iam.TestRepo(t, conn, wrapper) + _, proj := iam.TestScopes(t, iamRepo) + + cs := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0] + credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 2) + lib1 := credLibs[0] + lib2 := credLibs[1] + + setupFn := func(tar target.Target) ([]target.CredentialSource, []*target.CredentialLibrary) { + credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 10) + cls := make([]*target.CredentialLibrary, 0, len(credLibs)) + for _, cl := range credLibs { + cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), cl.PublicId, credential.ApplicationPurpose)) + } + + _, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls) + require.NoError(t, err) + require.Equal(t, 10, len(created)) + return created, cls + } + type args struct { + targetVersion uint32 + cls []*target.CredentialLibrary + addToOrigLibs bool + } + tests := []struct { + name string + setup func(target.Target) ([]target.CredentialSource, []*target.CredentialLibrary) + args args + wantAffectedRows int + wantErr bool + wantErrCode errors.Code + }{ + { + name: "clear", + setup: setupFn, + args: args{ + targetVersion: 2, + cls: []*target.CredentialLibrary{}, + }, + wantErr: false, + wantAffectedRows: 10, + }, + { + name: "no-change", + setup: setupFn, + args: args{ + targetVersion: 2, + cls: []*target.CredentialLibrary{}, + addToOrigLibs: true, + }, + wantErr: false, + wantAffectedRows: 0, + }, + { + name: "add-cred-sources", + setup: setupFn, + args: args{ + targetVersion: 2, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose), + }, + addToOrigLibs: true, + }, + wantErr: false, + wantAffectedRows: 2, + }, + { + name: "add-multiple-purposes", + setup: setupFn, + args: args{ + targetVersion: 2, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose), + target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose), + }, + addToOrigLibs: true, + }, + wantErr: false, + wantAffectedRows: 3, + }, + { + name: "remove-add-change-purpose", + setup: func(tar target.Target) ([]target.CredentialSource, []*target.CredentialLibrary) { + cls := []*target.CredentialLibrary{ + target.TestNewCredentialLibrary(tar.GetPublicId(), lib1.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary(tar.GetPublicId(), lib2.PublicId, credential.ApplicationPurpose), + } + + _, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls) + require.NoError(t, err) + require.Equal(t, 2, len(created)) + return created, cls + }, + args: args{ + targetVersion: 2, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose), + target.TestNewCredentialLibrary("", lib2.PublicId, credential.EgressPurpose), + }, + addToOrigLibs: false, + }, + wantErr: false, + wantAffectedRows: 4, + }, + { + name: "zero version", + setup: setupFn, + args: args{ + targetVersion: 0, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose), + }, + addToOrigLibs: true, + }, + wantErr: true, + wantErrCode: errors.InvalidParameter, + }, + { + name: "bad version", + setup: setupFn, + args: args{ + targetVersion: 1000, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose), + }, + addToOrigLibs: true, + }, + wantErr: true, + wantErrCode: errors.VersionMismatch, + }, + { + name: "remove existing and add cred libs", + setup: setupFn, + args: args{ + targetVersion: 2, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose), + }, + addToOrigLibs: false, + }, + wantErr: false, + wantAffectedRows: 12, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + + tar := targettest.TestNewTestTarget(t, conn, proj.PublicId, tt.name) + + var origCredSources []target.CredentialSource + var origCredLibraries []*target.CredentialLibrary + if tt.setup != nil { + origCredSources, origCredLibraries = tt.setup(tar) + } + + wantCredSources := make(map[string]*target.CredentialLibrary) + for _, cl := range tt.args.cls { + cl.TargetId = tar.GetPublicId() + wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = cl + } + if tt.args.addToOrigLibs { + tt.args.cls = append(tt.args.cls, origCredLibraries...) + for _, cl := range origCredLibraries { + wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = cl + } + } + + origTarget, _, lookupCredSources, err := repo.LookupTarget(context.Background(), tar.GetPublicId()) + require.NoError(err) + assert.Equal(origCredSources, lookupCredSources) + + _, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), tar.GetPublicId(), tt.args.targetVersion, tt.args.cls) + if tt.wantErr { + require.Error(err) + assert.Equal(0, affectedRows) + assert.Truef(errors.Match(errors.T(tt.wantErrCode), err), "unexpected error %s", err.Error()) + return + } + t.Log(err) + require.NoError(err) + assert.Equal(tt.wantAffectedRows, affectedRows) + + assert.Equal(len(wantCredSources), len(got)) + + for _, cs := range got { + w, ok := wantCredSources[cs.Id()+"_"+string(cs.CredentialPurpose())] + assert.True(ok, "got unexpected credentialsource %v", cs) + assert.Equal(w.CredentialLibraryId, cs.Id()) + assert.Equal(w.CredentialPurpose, string(cs.CredentialPurpose())) + } + + foundTarget, _, _, err := repo.LookupTarget(context.Background(), tar.GetPublicId()) + require.NoError(err) + if tt.name != "no-change" { + assert.Equalf(tt.args.targetVersion+1, foundTarget.GetVersion(), "%s unexpected version: %d/%d", tt.name, tt.args.targetVersion+1, foundTarget.GetVersion()) + assert.Equalf(origTarget.GetVersion(), foundTarget.GetVersion()-1, "%s unexpected version: %d/%d", tt.name, origTarget.GetVersion(), foundTarget.GetVersion()-1) + } + }) + } + t.Run("missing-target-id", func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + + cl1 := target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose) + _, _, _, err := repo.SetTargetCredentialSources(context.Background(), "", 1, []*target.CredentialLibrary{cl1}) + + require.Error(err) + assert.Truef(errors.Match(errors.T(errors.InvalidParameter), err), "unexpected error %s", err.Error()) + }) + t.Run("target-not-found", func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + + cl1 := target.TestNewCredentialLibrary("fake-target-id", lib1.PublicId, credential.ApplicationPurpose) + _, _, _, err := repo.SetTargetCredentialSources(context.Background(), "fake-target-id", 1, []*target.CredentialLibrary{cl1}) + + require.Error(err) + assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error()) + }) +} diff --git a/internal/target/targettest/store/target.pb.go b/internal/target/targettest/store/target.pb.go new file mode 100644 index 000000000..cb4e299fc --- /dev/null +++ b/internal/target/targettest/store/target.pb.go @@ -0,0 +1,307 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.17.3 +// source: controller/storage/target/targettest/store/v1/target.proto + +package store + +import ( + timestamp "github.com/hashicorp/boundary/internal/db/timestamp" + _ "github.com/hashicorp/boundary/sdk/pbs/controller/protooptions" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Target struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // public_id is used to access the targettest.Target via an API + // @inject_tag: gorm:"primary_key" + PublicId string `protobuf:"bytes,10,opt,name=public_id,json=publicId,proto3" json:"public_id,omitempty" gorm:"primary_key"` + // scope id for the targettest.Target + // @inject_tag: `gorm:"default:null"` + ScopeId string `protobuf:"bytes,20,opt,name=scope_id,json=scopeId,proto3" json:"scope_id,omitempty" gorm:"default:null"` + // name is the optional friendly name used to + // access the targettest.Target via an API + // @inject_tag: `gorm:"default:null"` + Name string `protobuf:"bytes,30,opt,name=name,proto3" json:"name,omitempty" gorm:"default:null"` + // description of the targettest.Target + // @inject_tag: `gorm:"default:null"` + Description string `protobuf:"bytes,40,opt,name=description,proto3" json:"description,omitempty" gorm:"default:null"` + // create_time from the RDBMS + // @inject_tag: `gorm:"default:current_timestamp"` + CreateTime *timestamp.Timestamp `protobuf:"bytes,50,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty" gorm:"default:current_timestamp"` + // update_time from the RDBMS + // @inject_tag: `gorm:"default:current_timestamp"` + UpdateTime *timestamp.Timestamp `protobuf:"bytes,60,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty" gorm:"default:current_timestamp"` + // version allows optimistic locking of the targettest.Target when modifying the + // targettest.Target + // @inject_tag: `gorm:"default:null"` + Version uint32 `protobuf:"varint,70,opt,name=version,proto3" json:"version,omitempty" gorm:"default:null"` + // default port of the targettest.Target + // @inject_tag: `gorm:"default:null"` + DefaultPort uint32 `protobuf:"varint,80,opt,name=default_port,json=defaultPort,proto3" json:"default_port,omitempty" gorm:"default:null"` + // Maximum total lifetime of a created session, in seconds + // @inject_tag: `gorm:"default:null"` + SessionMaxSeconds uint32 `protobuf:"varint,100,opt,name=session_max_seconds,json=sessionMaxSeconds,proto3" json:"session_max_seconds,omitempty" gorm:"default:null"` + // Maximum number of connections in a session + // @inject_tag: `gorm:"default:null"` + SessionConnectionLimit int32 `protobuf:"varint,110,opt,name=session_connection_limit,json=sessionConnectionLimit,proto3" json:"session_connection_limit,omitempty" gorm:"default:null"` + // A boolean expression that allows filtering the workers that can handle a session + // @inject_tag: `gorm:"default:null"` + WorkerFilter string `protobuf:"bytes,120,opt,name=worker_filter,json=workerFilter,proto3" json:"worker_filter,omitempty" gorm:"default:null"` +} + +func (x *Target) Reset() { + *x = Target{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_storage_target_targettest_store_v1_target_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Target) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Target) ProtoMessage() {} + +func (x *Target) ProtoReflect() protoreflect.Message { + mi := &file_controller_storage_target_targettest_store_v1_target_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Target.ProtoReflect.Descriptor instead. +func (*Target) Descriptor() ([]byte, []int) { + return file_controller_storage_target_targettest_store_v1_target_proto_rawDescGZIP(), []int{0} +} + +func (x *Target) GetPublicId() string { + if x != nil { + return x.PublicId + } + return "" +} + +func (x *Target) GetScopeId() string { + if x != nil { + return x.ScopeId + } + return "" +} + +func (x *Target) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Target) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Target) GetCreateTime() *timestamp.Timestamp { + if x != nil { + return x.CreateTime + } + return nil +} + +func (x *Target) GetUpdateTime() *timestamp.Timestamp { + if x != nil { + return x.UpdateTime + } + return nil +} + +func (x *Target) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *Target) GetDefaultPort() uint32 { + if x != nil { + return x.DefaultPort + } + return 0 +} + +func (x *Target) GetSessionMaxSeconds() uint32 { + if x != nil { + return x.SessionMaxSeconds + } + return 0 +} + +func (x *Target) GetSessionConnectionLimit() int32 { + if x != nil { + return x.SessionConnectionLimit + } + return 0 +} + +func (x *Target) GetWorkerFilter() string { + if x != nil { + return x.WorkerFilter + } + return "" +} + +var File_controller_storage_target_targettest_store_v1_target_proto protoreflect.FileDescriptor + +var file_controller_storage_target_targettest_store_v1_target_proto_rawDesc = []byte{ + 0x0a, 0x3a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2d, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x74, 0x65, + 0x73, 0x74, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc3, 0x05, 0x0a, 0x06, 0x54, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, + 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, 0x10, 0xc2, 0xdd, 0x29, 0x0c, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, + 0x12, 0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x2a, 0xc2, + 0xdd, 0x29, 0x26, 0x0a, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, + 0x12, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x5c, 0x0a, 0x13, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x64, 0x20, + 0x01, 0x28, 0x0d, 0x42, 0x2c, 0xc2, 0xdd, 0x29, 0x28, 0x0a, 0x11, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x13, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x52, 0x11, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x70, 0x0a, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x18, 0x6e, 0x20, 0x01, 0x28, 0x05, 0x42, 0x36, 0xc2, 0xdd, 0x29, 0x32, 0x0a, 0x16, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x12, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x16, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x46, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, + 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x78, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xc2, + 0xdd, 0x29, 0x1d, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x12, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x46, + 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_controller_storage_target_targettest_store_v1_target_proto_rawDescOnce sync.Once + file_controller_storage_target_targettest_store_v1_target_proto_rawDescData = file_controller_storage_target_targettest_store_v1_target_proto_rawDesc +) + +func file_controller_storage_target_targettest_store_v1_target_proto_rawDescGZIP() []byte { + file_controller_storage_target_targettest_store_v1_target_proto_rawDescOnce.Do(func() { + file_controller_storage_target_targettest_store_v1_target_proto_rawDescData = protoimpl.X.CompressGZIP(file_controller_storage_target_targettest_store_v1_target_proto_rawDescData) + }) + return file_controller_storage_target_targettest_store_v1_target_proto_rawDescData +} + +var file_controller_storage_target_targettest_store_v1_target_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_controller_storage_target_targettest_store_v1_target_proto_goTypes = []interface{}{ + (*Target)(nil), // 0: controller.storage.target.targettest.store.v1.Target + (*timestamp.Timestamp)(nil), // 1: controller.storage.timestamp.v1.Timestamp +} +var file_controller_storage_target_targettest_store_v1_target_proto_depIdxs = []int32{ + 1, // 0: controller.storage.target.targettest.store.v1.Target.create_time:type_name -> controller.storage.timestamp.v1.Timestamp + 1, // 1: controller.storage.target.targettest.store.v1.Target.update_time:type_name -> controller.storage.timestamp.v1.Timestamp + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_controller_storage_target_targettest_store_v1_target_proto_init() } +func file_controller_storage_target_targettest_store_v1_target_proto_init() { + if File_controller_storage_target_targettest_store_v1_target_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_controller_storage_target_targettest_store_v1_target_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Target); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_controller_storage_target_targettest_store_v1_target_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_controller_storage_target_targettest_store_v1_target_proto_goTypes, + DependencyIndexes: file_controller_storage_target_targettest_store_v1_target_proto_depIdxs, + MessageInfos: file_controller_storage_target_targettest_store_v1_target_proto_msgTypes, + }.Build() + File_controller_storage_target_targettest_store_v1_target_proto = out.File + file_controller_storage_target_targettest_store_v1_target_proto_rawDesc = nil + file_controller_storage_target_targettest_store_v1_target_proto_goTypes = nil + file_controller_storage_target_targettest_store_v1_target_proto_depIdxs = nil +} diff --git a/internal/target/targettest/target.go b/internal/target/targettest/target.go new file mode 100644 index 000000000..4109fa465 --- /dev/null +++ b/internal/target/targettest/target.go @@ -0,0 +1,262 @@ +// Package targettest provides a test target subtype for use by the target +// package. Note that it leverages the tcp.Target's database table to avoid +// needing schema migrations just for tests. +package targettest + +import ( + "context" + "testing" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/db/timestamp" + "github.com/hashicorp/boundary/internal/errors" + "github.com/hashicorp/boundary/internal/oplog" + "github.com/hashicorp/boundary/internal/target" + "github.com/hashicorp/boundary/internal/target/targettest/store" + "github.com/hashicorp/boundary/internal/types/subtypes" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" +) + +const ( + Subtype = subtypes.Subtype("tcp") + TargetPrefix = "ttcp" +) + +// Target is a target.Target used for tests. +type Target struct { + *store.Target + tableName string `gorm:"-"` +} + +var ( + _ target.Target = (*Target)(nil) + _ db.VetForWriter = (*Target)(nil) + _ oplog.ReplayableMessage = (*Target)(nil) +) + +// VetForWrite implements db.VetForWrite() interface and validates the tcp target +// before it's written. +func (t *Target) VetForWrite(ctx context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error { + const op = "target_test.(Target).VetForWrite" + if t.PublicId == "" { + return errors.New(ctx, errors.InvalidParameter, op, "missing public id") + } + if opType == db.CreateOp { + if t.ScopeId == "" { + return errors.New(ctx, errors.InvalidParameter, op, "missing scope id") + } + if t.Name == "" { + return errors.New(ctx, errors.InvalidParameter, op, "missing name") + } + } + return nil +} + +// TableName returns the tablename to override the default gorm table name +func (t *Target) TableName() string { + if t.tableName != "" { + return t.tableName + } + return "target_tcp" +} + +// SetTableName sets the tablename and satisfies the ReplayableMessage +// interface. If the caller attempts to set the name to "" the name will be +// reset to the default name. +func (t *Target) SetTableName(n string) { + t.tableName = n +} + +func (t *Target) GetPublicId() string { + return t.PublicId +} + +func (t *Target) GetScopeId() string { + return t.ScopeId +} + +func (t *Target) GetDefaultPort() uint32 { + return t.DefaultPort +} + +func (t *Target) GetName() string { + return t.Name +} + +func (t *Target) GetDescription() string { + return t.Description +} + +func (t *Target) GetVersion() uint32 { + return t.Version +} + +func (t *Target) GetType() subtypes.Subtype { + return Subtype +} + +func (t *Target) GetCreateTime() *timestamp.Timestamp { + return t.CreateTime +} + +func (t *Target) GetUpdateTime() *timestamp.Timestamp { + return t.UpdateTime +} + +func (t *Target) GetSessionMaxSeconds() uint32 { + return t.SessionMaxSeconds +} + +func (t *Target) GetSessionConnectionLimit() int32 { + return t.SessionConnectionLimit +} + +func (t *Target) GetWorkerFilter() string { + return t.WorkerFilter +} + +func (t *Target) Clone() target.Target { + cp := proto.Clone(t.Target) + return &Target{ + Target: cp.(*store.Target), + } +} + +func (t *Target) SetPublicId(_ context.Context, publicId string) error { + t.PublicId = publicId + return nil +} + +func (t *Target) SetScopeId(scopeId string) { + t.ScopeId = scopeId +} + +func (t *Target) SetName(name string) { + t.Name = name +} + +func (t *Target) SetDescription(description string) { + t.Description = description +} + +func (t *Target) SetVersion(v uint32) { + t.Version = v +} + +func (t *Target) SetDefaultPort(port uint32) { + t.DefaultPort = port +} + +func (t *Target) SetCreateTime(ts *timestamp.Timestamp) { + t.CreateTime = ts +} + +func (t *Target) SetUpdateTime(ts *timestamp.Timestamp) { + t.UpdateTime = ts +} + +func (t *Target) SetSessionMaxSeconds(s uint32) { + t.SessionMaxSeconds = s +} + +func (t *Target) SetSessionConnectionLimit(l int32) { + t.SessionConnectionLimit = l +} + +func (t *Target) SetWorkerFilter(f string) { + t.WorkerFilter = f +} + +func (t *Target) Oplog(op oplog.OpType) oplog.Metadata { + return oplog.Metadata{ + "resource-public-id": []string{t.PublicId}, + "resource-type": []string{"tcp target"}, + "op-type": []string{op.String()}, + "scope-id": []string{t.ScopeId}, + } +} + +// Alloc creates an in-memory Target. +func Alloc() target.Target { + return &Target{ + Target: &store.Target{}, + } +} + +// Vet checks that the given Target is a targettest.Target and that it is not nil. +func Vet(ctx context.Context, t target.Target) error { + const op = "targettest.Vet" + + tt, ok := t.(*Target) + if !ok { + return errors.New(ctx, errors.InvalidParameter, op, "target is not a tcp.Target") + } + + if tt == nil { + return errors.New(ctx, errors.InvalidParameter, op, "missing target") + } + + if tt.Target == nil { + return errors.New(ctx, errors.InvalidParameter, op, "missing target store") + } + return nil +} + +// New creates a targettest.Target. +func New(scopeId string, opt ...target.Option) (*Target, error) { + const op = "target_test.New" + opts := target.GetOpts(opt...) + if scopeId == "" { + return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing scope id") + } + t := &Target{ + Target: &store.Target{ + ScopeId: scopeId, + Name: opts.WithName, + Description: opts.WithDescription, + DefaultPort: opts.WithDefaultPort, + SessionConnectionLimit: opts.WithSessionConnectionLimit, + SessionMaxSeconds: opts.WithSessionMaxSeconds, + WorkerFilter: opts.WithWorkerFilter, + }, + } + return t, nil +} + +// TestNewTestTarget is a test helper for creating a targettest.Target. +func TestNewTestTarget(t *testing.T, conn *db.DB, scopeId, name string, opt ...target.Option) *Target { + t.Helper() + opt = append(opt, target.WithName(name)) + opts := target.GetOpts(opt...) + require := require.New(t) + rw := db.New(conn) + tar, err := New(scopeId, opt...) + require.NoError(err) + id, err := db.NewPublicId(TargetPrefix) + require.NoError(err) + tar.PublicId = id + err = rw.Create(context.Background(), tar) + require.NoError(err) + + if len(opts.WithHostSources) > 0 { + newHostSets := make([]interface{}, 0, len(opts.WithHostSources)) + for _, s := range opts.WithHostSources { + hostSet, err := target.NewTargetHostSet(tar.PublicId, s) + require.NoError(err) + newHostSets = append(newHostSets, hostSet) + } + err := rw.CreateItems(context.Background(), newHostSets) + require.NoError(err) + } + if len(opts.WithCredentialLibraries) > 0 { + newCredLibs := make([]interface{}, 0, len(opts.WithCredentialLibraries)) + for _, cl := range opts.WithCredentialLibraries { + cl.TargetId = tar.PublicId + newCredLibs = append(newCredLibs, cl) + } + err := rw.CreateItems(context.Background(), newCredLibs) + require.NoError(err) + } + return tar +} diff --git a/internal/target/tcp/repository_credential_source_test.go b/internal/target/tcp/repository_credential_source_test.go index ba0720773..7d1077c14 100644 --- a/internal/target/tcp/repository_credential_source_test.go +++ b/internal/target/tcp/repository_credential_source_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/hashicorp/boundary/internal/credential" "github.com/hashicorp/boundary/internal/credential/vault" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" @@ -106,7 +107,12 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) { assert, require := assert.New(t), require.New(t) projTarget := tcp.TestTarget(t, conn, staticProj.PublicId, tt.name) - gotTarget, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, tt.args.targetVersion, tt.args.credLibIds) + credLibs := make([]*target.CredentialLibrary, 0, len(tt.args.credLibIds)) + for _, clid := range tt.args.credLibIds { + credLibs = append(credLibs, target.TestNewCredentialLibrary(projTarget.PublicId, clid, credential.ApplicationPurpose)) + } + + gotTarget, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, tt.args.targetVersion, credLibs) if tt.wantErr { require.Error(err) assert.Truef(errors.Match(errors.T(tt.wantErrCode), err), "unexpected error %s", err.Error()) @@ -142,18 +148,22 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) { assert, require := assert.New(t), require.New(t) projTarget := tcp.TestTarget(t, conn, staticProj.PublicId, "add-existing") - _, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []string{lib1.PublicId}) + cl1 := target.TestNewCredentialLibrary(projTarget.PublicId, lib1.PublicId, credential.ApplicationPurpose) + cl2 := target.TestNewCredentialLibrary(projTarget.PublicId, lib2.PublicId, credential.ApplicationPurpose) + cl3 := target.TestNewCredentialLibrary(projTarget.PublicId, lib3.PublicId, credential.ApplicationPurpose) + + _, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []*target.CredentialLibrary{cl1}) require.NoError(err) assert.Len(gotCredSources, 1) assert.Equal(lib1.PublicId, gotCredSources[0].Id()) // Adding lib1 again should error - _, _, _, err = repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []string{lib1.PublicId}) + _, _, _, err = repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []*target.CredentialLibrary{cl1}) require.Error(err) assert.True(errors.Match(errors.T(errors.NotUnique), err)) // Adding multiple with lib1 in set should error - _, _, _, err = repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []string{lib3.PublicId, lib2.PublicId, lib1.PublicId}) + _, _, _, err = repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []*target.CredentialLibrary{cl3, cl2, cl1}) require.Error(err) assert.True(errors.Match(errors.T(errors.NotUnique), err)) @@ -166,7 +176,8 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) { t.Run("target-not-found", func(t *testing.T) { assert, require := assert.New(t), require.New(t) - _, _, _, err := repo.AddTargetCredentialSources(context.Background(), "fake-target-id", 1, []string{lib1.PublicId}) + cl1 := target.TestNewCredentialLibrary("fake-target-id", lib1.PublicId, credential.ApplicationPurpose) + _, _, _, err := repo.AddTargetCredentialSources(context.Background(), "fake-target-id", 1, []*target.CredentialLibrary{cl1}) require.Error(err) assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error()) @@ -275,29 +286,29 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) { assert, require := assert.New(t), require.New(t) cs := css[i] - target := tcp.TestTarget(t, conn, proj.PublicId, tt.name) + tar := tcp.TestTarget(t, conn, proj.PublicId, tt.name) - clIds := make([]string, 0, tt.args.createCnt) + cls := make([]*target.CredentialLibrary, 0, tt.args.createCnt) if tt.args.createCnt > 0 { credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.PublicId, tt.args.createCnt) for _, cl := range credLibs { - clIds = append(clIds, cl.PublicId) + cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), cl.PublicId, credential.ApplicationPurpose)) } } - _, _, addedCredSources, err := repo.AddTargetCredentialSources(context.Background(), target.GetPublicId(), 1, clIds) + _, _, addedCredSources, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls) require.NoError(err) assert.Equal(tt.args.createCnt, len(addedCredSources)) - deleteCredSources := make([]string, 0, tt.args.deleteCnt) + deleteCredSources := make([]*target.CredentialLibrary, 0, tt.args.deleteCnt) for i := 0; i < tt.args.deleteCnt; i++ { - deleteCredSources = append(deleteCredSources, clIds[i]) + deleteCredSources = append(deleteCredSources, cls[i]) } var targetId string switch { case tt.args.targetIdOverride != nil: targetId = *tt.args.targetIdOverride default: - targetId = target.GetPublicId() + targetId = tar.GetPublicId() } var targetVersion uint32 switch { @@ -317,7 +328,7 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) { assert.Equal(tt.wantRowsDeleted, deletedRows) // we should find the oplog for the delete of target credential libraries - err = db.TestVerifyOplog(t, rw, target.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) + err = db.TestVerifyOplog(t, rw, tar.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)) assert.NoError(err) }) } @@ -333,18 +344,22 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) { lib3 := libs[2] projTarget := tcp.TestTarget(t, conn, proj.PublicId, "add-existing") - _, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []string{lib1.PublicId, lib2.PublicId}) + cl1 := target.TestNewCredentialLibrary(projTarget.PublicId, lib1.PublicId, credential.ApplicationPurpose) + cl2 := target.TestNewCredentialLibrary(projTarget.PublicId, lib2.PublicId, credential.ApplicationPurpose) + cl3 := target.TestNewCredentialLibrary(projTarget.PublicId, lib3.PublicId, credential.ApplicationPurpose) + + _, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []*target.CredentialLibrary{cl1, cl2}) require.NoError(err) assert.Len(gotCredSources, 2) // Deleting an unassociated source should return an error - delCount, err := repo.DeleteTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []string{lib3.PublicId}) + delCount, err := repo.DeleteTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []*target.CredentialLibrary{cl3}) require.Error(err) assert.True(errors.Match(errors.T(errors.MultipleRecords), err)) assert.Equal(0, delCount) // Deleting sources which includes an unassociated source should return an error - delCount, err = repo.DeleteTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []string{lib1.PublicId, lib2.PublicId, lib3.PublicId}) + delCount, err = repo.DeleteTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []*target.CredentialLibrary{cl1, cl2, cl3}) require.Error(err) assert.True(errors.Match(errors.T(errors.MultipleRecords), err)) assert.Equal(0, delCount) @@ -373,17 +388,17 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { lib1 := credLibs[0] lib2 := credLibs[1] - setupFn := func(target target.Target) []target.CredentialSource { + setupFn := func(tar target.Target) ([]target.CredentialSource, []*target.CredentialLibrary) { credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 10) - clIds := make([]string, 0, len(credLibs)) + cls := make([]*target.CredentialLibrary, 0, len(credLibs)) for _, cl := range credLibs { - clIds = append(clIds, cl.PublicId) + cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), cl.PublicId, credential.ApplicationPurpose)) } - _, _, created, err := repo.AddTargetCredentialSources(context.Background(), target.GetPublicId(), 1, clIds) + _, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls) require.NoError(t, err) require.Equal(t, 10, len(created)) - return created + return created, cls } type args struct { targetVersion uint32 @@ -392,7 +407,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { } tests := []struct { name string - setup func(target.Target) []target.CredentialSource + setup func(target.Target) ([]target.CredentialSource, []*target.CredentialLibrary) args args wantAffectedRows int wantErr bool @@ -471,22 +486,29 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { tar := tcp.TestTarget(t, conn, proj.PublicId, tt.name) var origCredSources []target.CredentialSource + var origCredLibraries []*target.CredentialLibrary if tt.setup != nil { - origCredSources = tt.setup(tar) + origCredSources, origCredLibraries = tt.setup(tar) } + + cls := make([]*target.CredentialLibrary, 0, len(tt.args.clIds)) + for _, clid := range tt.args.clIds { + cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), clid, credential.ApplicationPurpose)) + } + var wantIds []string + wantIds = append(wantIds, tt.args.clIds...) if tt.args.addToOrigLibs { - origIds := make([]string, 0, len(origCredSources)) - for _, cl := range origCredSources { - origIds = append(origIds, cl.Id()) + cls = append(cls, origCredLibraries...) + for _, cl := range origCredLibraries { + wantIds = append(wantIds, cl.CredentialLibraryId) } - tt.args.clIds = append(tt.args.clIds, origIds...) } origTarget, _, lookupCredSources, err := repo.LookupTarget(context.Background(), tar.GetPublicId()) require.NoError(err) assert.Equal(origCredSources, lookupCredSources) - _, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), tar.GetPublicId(), tt.args.targetVersion, tt.args.clIds) + _, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), tar.GetPublicId(), tt.args.targetVersion, cls) if tt.wantErr { require.Error(err) assert.Equal(0, affectedRows) @@ -496,10 +518,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { t.Log(err) require.NoError(err) assert.Equal(tt.wantAffectedRows, affectedRows) - assert.Equal(len(tt.args.clIds), len(got)) - var wantIds []string - wantIds = append(wantIds, tt.args.clIds...) + assert.Equal(len(wantIds), len(got)) sort.Strings(wantIds) var gotIds []string @@ -523,7 +543,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { t.Run("missing-target-id", func(t *testing.T) { assert, require := assert.New(t), require.New(t) - _, _, _, err := repo.SetTargetCredentialSources(context.Background(), "", 1, []string{lib1.PublicId}) + cl1 := target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose) + _, _, _, err := repo.SetTargetCredentialSources(context.Background(), "", 1, []*target.CredentialLibrary{cl1}) require.Error(err) assert.Truef(errors.Match(errors.T(errors.InvalidParameter), err), "unexpected error %s", err.Error()) @@ -531,7 +552,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { t.Run("target-not-found", func(t *testing.T) { assert, require := assert.New(t), require.New(t) - _, _, _, err := repo.SetTargetCredentialSources(context.Background(), "fake-target-id", 1, []string{lib1.PublicId}) + cl1 := target.TestNewCredentialLibrary("fake-target-id", lib1.PublicId, credential.ApplicationPurpose) + _, _, _, err := repo.SetTargetCredentialSources(context.Background(), "fake-target-id", 1, []*target.CredentialLibrary{cl1}) require.Error(err) assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error()) diff --git a/internal/target/tcp/repository_tcp_target_test.go b/internal/target/tcp/repository_tcp_target_test.go index 6ae271b5c..9b2338a67 100644 --- a/internal/target/tcp/repository_tcp_target_test.go +++ b/internal/target/tcp/repository_tcp_target_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/hashicorp/boundary/internal/credential" "github.com/hashicorp/boundary/internal/credential/vault" "github.com/hashicorp/boundary/internal/db" dbassert "github.com/hashicorp/boundary/internal/db/assert" @@ -14,6 +15,7 @@ import ( "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/oplog" "github.com/hashicorp/boundary/internal/target" + "github.com/hashicorp/boundary/internal/target/store" "github.com/hashicorp/boundary/internal/target/tcp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -39,9 +41,16 @@ func TestRepository_CreateTarget(t *testing.T) { cs := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0] credSources := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 2) - var clIds []string + var credLibraries []*target.CredentialLibrary + var credLibIds []string for _, cl := range credSources { - clIds = append(clIds, cl.PublicId) + credLibraries = append(credLibraries, &target.CredentialLibrary{ + CredentialLibrary: &store.CredentialLibrary{ + CredentialLibraryId: cl.PublicId, + CredentialPurpose: string(credential.ApplicationPurpose), + }, + }) + credLibIds = append(credLibIds, cl.PublicId) } type args struct { @@ -392,11 +401,22 @@ func TestRepository_UpdateTcpTarget(t *testing.T) { cls := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 5) var testClIds []string + var testCredLibs []*target.CredentialLibrary for _, cl := range cls { + testCredLibs = append(testCredLibs, &target.CredentialLibrary{ + CredentialLibrary: &store.CredentialLibrary{ + CredentialLibraryId: cl.PublicId, + CredentialPurpose: string(credential.ApplicationPurpose), + }, + }) testClIds = append(testClIds, cl.PublicId) } - tt.newTargetOpts = append(tt.newTargetOpts, target.WithHostSources(testHostSetIds), target.WithCredentialSources(testClIds)) + tt.newTargetOpts = append( + tt.newTargetOpts, + target.WithHostSources(testHostSetIds), + target.WithCredentialLibraries(testCredLibs), + ) name := tt.newName if name == "" { name = tcp.TestId(t) diff --git a/internal/target/tcp/testing.go b/internal/target/tcp/testing.go index f78f61e9b..6e917abd4 100644 --- a/internal/target/tcp/testing.go +++ b/internal/target/tcp/testing.go @@ -36,12 +36,11 @@ func TestTarget(t *testing.T, conn *db.DB, scopeId, name string, opt ...target.O err := rw.CreateItems(context.Background(), newHostSets) require.NoError(err) } - if len(opts.WithCredentialSources) > 0 { - newCredLibs := make([]interface{}, 0, len(opts.WithCredentialSources)) - for _, cl := range opts.WithCredentialSources { - newCl, err := target.NewCredentialLibrary(tar.PublicId, cl) - require.NoError(err) - newCredLibs = append(newCredLibs, newCl) + if len(opts.WithCredentialLibraries) > 0 { + newCredLibs := make([]interface{}, 0, len(opts.WithCredentialLibraries)) + for _, cl := range opts.WithCredentialLibraries { + cl.TargetId = tar.PublicId + newCredLibs = append(newCredLibs, cl) } err := rw.CreateItems(context.Background(), newCredLibs) require.NoError(err) diff --git a/internal/target/testing.go b/internal/target/testing.go index b436a7963..9460fd382 100644 --- a/internal/target/testing.go +++ b/internal/target/testing.go @@ -4,19 +4,33 @@ import ( "context" "testing" + "github.com/hashicorp/boundary/internal/credential" "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/target/store" "github.com/stretchr/testify/require" ) +// TestNewCredentialLibrary creates a new in memory CredentialLibrary +// representing the relationship between targetId and credentialLibraryId with +// the given purpose. +func TestNewCredentialLibrary(targetId, credentialLibraryId string, purpose credential.Purpose) *CredentialLibrary { + return &CredentialLibrary{ + CredentialLibrary: &store.CredentialLibrary{ + TargetId: targetId, + CredentialLibraryId: credentialLibraryId, + CredentialPurpose: string(purpose), + }, + } +} + // TestCredentialLibrary creates a CredentialLibrary for targetId and -// libraryId. +// libraryId with the credential purpose of application. func TestCredentialLibrary(t *testing.T, conn *db.DB, targetId, libraryId string) *CredentialLibrary { t.Helper() require := require.New(t) rw := db.New(conn) - lib, err := NewCredentialLibrary(targetId, libraryId) - require.NoError(err) - err = rw.Create(context.Background(), lib) + lib := TestNewCredentialLibrary(targetId, libraryId, credential.ApplicationPurpose) + err := rw.Create(context.Background(), lib) require.NoError(err) return lib } From 1b7cfb170450d1454f699ba2cb713dd88c0eb0e4 Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Tue, 12 Oct 2021 10:53:33 -0400 Subject: [PATCH 04/15] feat(target): Add support for credential library validation Target subtypes must now implement another repository hook to validate any CredentialLibraries that are being added/set. This allows for subtypes to determine the valid set of CredentialLibraries. For tcp.Targets only CredentialLibaries with credential.ApplicationPurpose are allowed. If any other purpose is provided an error is returned. --- .../migrations/oss/postgres_16_05_test.go | 6 +- internal/session/repository_session_test.go | 6 +- internal/target/registry.go | 28 ++- .../target/repository_credential_source.go | 17 ++ .../repository_credential_source_test.go | 16 +- internal/target/targettest/target.go | 5 + internal/target/tcp/register.go | 17 +- .../tcp/repository_credential_source_test.go | 208 +++++++++++++----- 8 files changed, 227 insertions(+), 76 deletions(-) diff --git a/internal/db/schema/migrations/oss/postgres_16_05_test.go b/internal/db/schema/migrations/oss/postgres_16_05_test.go index b63444085..a6c4bc081 100644 --- a/internal/db/schema/migrations/oss/postgres_16_05_test.go +++ b/internal/db/schema/migrations/oss/postgres_16_05_test.go @@ -168,8 +168,7 @@ func testSessionCredentialParams(t *testing.T, conn *db.DB, kms *kms.Kms, wrappe libIds := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2) libs := []*target.CredentialLibrary{ target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.ApplicationPurpose), - target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.IngressPurpose), - target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), credential.EgressPurpose), + target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), credential.ApplicationPurpose), } targetRepo, err := target.NewRepository(rw, rw, kms) @@ -178,8 +177,7 @@ func testSessionCredentialParams(t *testing.T, conn *db.DB, kms *kms.Kms, wrappe require.NoError(t, err) creds := []*session.DynamicCredential{ session.NewDynamicCredential(libIds[0].GetPublicId(), credential.ApplicationPurpose), - session.NewDynamicCredential(libIds[0].GetPublicId(), credential.IngressPurpose), - session.NewDynamicCredential(libIds[1].GetPublicId(), credential.EgressPurpose), + session.NewDynamicCredential(libIds[1].GetPublicId(), credential.ApplicationPurpose), } return creds } diff --git a/internal/session/repository_session_test.go b/internal/session/repository_session_test.go index f2107a71d..1bc59ee9d 100644 --- a/internal/session/repository_session_test.go +++ b/internal/session/repository_session_test.go @@ -1661,16 +1661,14 @@ func testSessionCredentialParams(t *testing.T, conn *db.DB, wrapper wrapping.Wra libIds := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2) libs := []*target.CredentialLibrary{ target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.ApplicationPurpose), - target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.IngressPurpose), - target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), credential.EgressPurpose), + target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), credential.ApplicationPurpose), } _, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tar.GetPublicId(), tar.GetVersion(), libs) require.NoError(err) creds := []*DynamicCredential{ NewDynamicCredential(libIds[0].GetPublicId(), credential.ApplicationPurpose), - NewDynamicCredential(libIds[0].GetPublicId(), credential.IngressPurpose), - NewDynamicCredential(libIds[1].GetPublicId(), credential.EgressPurpose), + NewDynamicCredential(libIds[1].GetPublicId(), credential.ApplicationPurpose), } params.DynamicCredentials = creds return params diff --git a/internal/target/registry.go b/internal/target/registry.go index d33f3035c..333cdd725 100644 --- a/internal/target/registry.go +++ b/internal/target/registry.go @@ -15,10 +15,15 @@ type AllocFunc func() Target // be used by the Repository. type VetFunc func(context.Context, Target) error +// VetCredentialLibrariesFunc is a function that checks the given CredentialLibraries +// to ensure that they are valid for a Target subtype. +type VetCredentialLibrariesFunc func(context.Context, []*CredentialLibrary) error + type registryEntry struct { - alloc AllocFunc - vet VetFunc - prefix string + alloc AllocFunc + vet VetFunc + vetCredentialLibraries VetCredentialLibrariesFunc + prefix string } type registry struct { @@ -71,6 +76,14 @@ func (r *registry) vetFunc(s subtypes.Subtype) (VetFunc, bool) { return entry.vet, ok } +func (r *registry) vetCredentialLibrariesFunc(s subtypes.Subtype) (VetCredentialLibrariesFunc, bool) { + entry, ok := r.get(s) + if !ok { + return nil, ok + } + return entry.vetCredentialLibraries, ok +} + func (r *registry) idPrefix(s subtypes.Subtype) (string, bool) { entry, ok := r.get(s) if !ok { @@ -103,10 +116,11 @@ func SubtypeFromId(id string) subtypes.Subtype { // Register registers repository hooks and the prefixes for a provided Subtype. Register // panics if the subtype has already been registered or if any of the // prefixes are associated with another subtype. -func Register(s subtypes.Subtype, af AllocFunc, vf VetFunc, prefix string) { +func Register(s subtypes.Subtype, af AllocFunc, vf VetFunc, vclf VetCredentialLibrariesFunc, prefix string) { subtypeRegistry.set(s, ®istryEntry{ - alloc: af, - vet: vf, - prefix: prefix, + alloc: af, + vet: vf, + vetCredentialLibraries: vclf, + prefix: prefix, }) } diff --git a/internal/target/repository_credential_source.go b/internal/target/repository_credential_source.go index 2cad2a345..8d158b885 100644 --- a/internal/target/repository_credential_source.go +++ b/internal/target/repository_credential_source.go @@ -74,6 +74,14 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type)) } + vetCredentialLibraries, ok := subtypeRegistry.vetCredentialLibrariesFunc(t.Subtype()) + if !ok { + return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type)) + } + if err := vetCredentialLibraries(ctx, cls); err != nil { + return nil, nil, nil, err + } + target := alloc() target.SetPublicId(ctx, t.PublicId) target.SetVersion(targetVersion + 1) @@ -284,6 +292,15 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st if !ok { return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type)) } + + vetCredentialLibraries, ok := subtypeRegistry.vetCredentialLibrariesFunc(t.Subtype()) + if !ok { + return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("%s is an unsupported target type %s", t.PublicId, t.Type)) + } + if err := vetCredentialLibraries(ctx, cls); err != nil { + return nil, nil, db.NoRowsAffected, err + } + target := alloc() target.SetPublicId(ctx, t.PublicId) target.SetVersion(targetVersion + 1) diff --git a/internal/target/repository_credential_source_test.go b/internal/target/repository_credential_source_test.go index 46cf8985c..d03c438f8 100644 --- a/internal/target/repository_credential_source_test.go +++ b/internal/target/repository_credential_source_test.go @@ -17,7 +17,7 @@ import ( ) func TestRepository_SetTargetCredentialSources(t *testing.T) { - target.Register(targettest.Subtype, targettest.Alloc, targettest.Vet, targettest.TargetPrefix) + target.Register(targettest.Subtype, targettest.Alloc, targettest.Vet, targettest.VetCredentialLibraries, targettest.TargetPrefix) t.Parallel() conn, _ := db.TestSetup(t, "postgres") @@ -189,15 +189,19 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { origCredSources, origCredLibraries = tt.setup(tar) } - wantCredSources := make(map[string]*target.CredentialLibrary) + wantCredSources := make(map[string]target.CredentialSource) for _, cl := range tt.args.cls { cl.TargetId = tar.GetPublicId() - wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = cl + wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = &target.TargetLibrary{ + CredentialLibrary: cl.CredentialLibrary, + } } if tt.args.addToOrigLibs { tt.args.cls = append(tt.args.cls, origCredLibraries...) for _, cl := range origCredLibraries { - wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = cl + wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = &target.TargetLibrary{ + CredentialLibrary: cl.CredentialLibrary, + } } } @@ -221,8 +225,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { for _, cs := range got { w, ok := wantCredSources[cs.Id()+"_"+string(cs.CredentialPurpose())] assert.True(ok, "got unexpected credentialsource %v", cs) - assert.Equal(w.CredentialLibraryId, cs.Id()) - assert.Equal(w.CredentialPurpose, string(cs.CredentialPurpose())) + assert.Equal(w.Id(), cs.Id()) + assert.Equal(w.CredentialPurpose(), cs.CredentialPurpose()) } foundTarget, _, _, err := repo.LookupTarget(context.Background(), tar.GetPublicId()) diff --git a/internal/target/targettest/target.go b/internal/target/targettest/target.go index 4109fa465..4d9b3e31b 100644 --- a/internal/target/targettest/target.go +++ b/internal/target/targettest/target.go @@ -203,6 +203,11 @@ func Vet(ctx context.Context, t target.Target) error { return nil } +// VetCredentialLibraries allows for any CredentialLibraries. +func VetCredentialLibraries(_ context.Context, _ []*target.CredentialLibrary) error { + return nil +} + // New creates a targettest.Target. func New(scopeId string, opt ...target.Option) (*Target, error) { const op = "target_test.New" diff --git a/internal/target/tcp/register.go b/internal/target/tcp/register.go index 68508d430..943ff8ac8 100644 --- a/internal/target/tcp/register.go +++ b/internal/target/tcp/register.go @@ -2,13 +2,15 @@ package tcp import ( "context" + "fmt" + "github.com/hashicorp/boundary/internal/credential" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/target" ) func init() { - target.Register(Subtype, allocTarget, vet, TargetPrefix) + target.Register(Subtype, allocTarget, vet, vetCredentialLibraries, TargetPrefix) } const ( @@ -35,3 +37,16 @@ func vet(ctx context.Context, t target.Target) error { } return nil } + +// vetCredentialLibraries checks that all of the provided credential libriaries have a CredentialPurpose +// of ApplicationPurpose. Any other CredentialPurpose will result in an error. +func vetCredentialLibraries(ctx context.Context, cls []*target.CredentialLibrary) error { + const op = "tcp.vetCredentialLibraries" + + for _, cl := range cls { + if cl.CredentialPurpose != string(credential.ApplicationPurpose) { + return errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("tcp.Target only supports credential purpose: %q", credential.ApplicationPurpose)) + } + } + return nil +} diff --git a/internal/target/tcp/repository_credential_source_test.go b/internal/target/tcp/repository_credential_source_test.go index 7d1077c14..1b0c80b28 100644 --- a/internal/target/tcp/repository_credential_source_test.go +++ b/internal/target/tcp/repository_credential_source_test.go @@ -2,7 +2,6 @@ package tcp_test import ( "context" - "sort" "testing" "time" @@ -14,6 +13,7 @@ import ( "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/oplog" "github.com/hashicorp/boundary/internal/target" + "github.com/hashicorp/boundary/internal/target/store" "github.com/hashicorp/boundary/internal/target/tcp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -40,14 +40,14 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) { type args struct { targetVersion uint32 - credLibIds []string + cls []*target.CredentialLibrary } tests := []struct { - name string - args args - wantCredLibIds []string - wantErr bool - wantErrCode errors.Code + name string + args args + wantCredSources map[string]target.CredentialSource + wantErr bool + wantErrCode errors.Code }{ { name: "zero-version", @@ -69,34 +69,95 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) { name: "valid-single-source", args: args{ targetVersion: 1, - credLibIds: []string{lib1.PublicId}, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + }, }, - wantCredLibIds: []string{lib1.PublicId}, - wantErr: false, + wantCredSources: map[string]target.CredentialSource{ + lib1.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetLibrary{ + CredentialLibrary: &store.CredentialLibrary{ + CredentialLibraryId: lib1.PublicId, + CredentialPurpose: string(credential.ApplicationPurpose), + }, + }, + }, + wantErr: false, }, { name: "valid-multiple-sources", args: args{ targetVersion: 1, - credLibIds: []string{lib1.PublicId, lib2.PublicId, lib3.PublicId}, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib3.PublicId, credential.ApplicationPurpose), + }, }, - wantCredLibIds: []string{lib1.PublicId, lib2.PublicId, lib3.PublicId}, - wantErr: false, + wantCredSources: map[string]target.CredentialSource{ + lib1.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetLibrary{ + CredentialLibrary: &store.CredentialLibrary{ + CredentialLibraryId: lib1.PublicId, + CredentialPurpose: string(credential.ApplicationPurpose), + }, + }, + lib2.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetLibrary{ + CredentialLibrary: &store.CredentialLibrary{ + CredentialLibraryId: lib2.PublicId, + CredentialPurpose: string(credential.ApplicationPurpose), + }, + }, + lib3.PublicId + "_" + string(credential.ApplicationPurpose): &target.TargetLibrary{ + CredentialLibrary: &store.CredentialLibrary{ + CredentialLibraryId: lib3.PublicId, + CredentialPurpose: string(credential.ApplicationPurpose), + }, + }, + }, + wantErr: false, }, { name: "invalid-source-id", args: args{ targetVersion: 1, - credLibIds: []string{lib1.PublicId, lib2.PublicId, lib3.PublicId, "invalid-source-id"}, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib3.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", "invalid-source-id", credential.ApplicationPurpose), + }, }, wantErr: true, wantErrCode: errors.NotSpecificIntegrity, }, + { + name: "egress-credential-purpose", + args: args{ + targetVersion: 1, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose), + }, + }, + wantErr: true, + wantErrCode: errors.InvalidParameter, + }, + { + name: "ingress-credential-purpose", + args: args{ + targetVersion: 1, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.IngressPurpose), + }, + }, + wantErr: true, + wantErrCode: errors.InvalidParameter, + }, { name: "bad-version", args: args{ targetVersion: 1000, - credLibIds: []string{lib1.PublicId}, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + }, }, wantErr: true, wantErrCode: errors.VersionMismatch, @@ -107,25 +168,25 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) { assert, require := assert.New(t), require.New(t) projTarget := tcp.TestTarget(t, conn, staticProj.PublicId, tt.name) - credLibs := make([]*target.CredentialLibrary, 0, len(tt.args.credLibIds)) - for _, clid := range tt.args.credLibIds { - credLibs = append(credLibs, target.TestNewCredentialLibrary(projTarget.PublicId, clid, credential.ApplicationPurpose)) + + for _, cl := range tt.args.cls { + cl.TargetId = projTarget.PublicId } - gotTarget, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, tt.args.targetVersion, credLibs) + gotTarget, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, tt.args.targetVersion, tt.args.cls) if tt.wantErr { require.Error(err) assert.Truef(errors.Match(errors.T(tt.wantErrCode), err), "unexpected error %s", err.Error()) return } require.NoError(err) - assert.Len(gotCredSources, len(tt.wantCredLibIds)) - gotCredSourcesMap := map[string]target.CredentialSource{} - for _, s := range gotCredSources { - gotCredSourcesMap[s.Id()] = s - } - for _, id := range tt.wantCredLibIds { - assert.NotEmpty(gotCredSourcesMap[id]) + assert.Len(gotCredSources, len(tt.wantCredSources)) + + for _, cs := range gotCredSources { + w, ok := tt.wantCredSources[cs.Id()+"_"+string(cs.CredentialPurpose())] + assert.True(ok, "got unexpected credentialsource %v", cs) + assert.Equal(w.Id(), cs.Id()) + assert.Equal(w.CredentialPurpose(), cs.CredentialPurpose()) } // test to see of the target version update oplog was created @@ -138,9 +199,13 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) { assert.Equal(projTarget.GetVersion(), tar.GetVersion()-1) assert.True(proto.Equal(gotTarget.(*tcp.Target), tar.(*tcp.Target))) assert.Equal(gotCredSources, lookupCredSources) - for _, s := range lookupCredSources { - assert.NotEmpty(gotCredSourcesMap[s.Id()]) - assert.Equal(projTarget.PublicId, s.TargetId()) + + for _, cs := range lookupCredSources { + w, ok := tt.wantCredSources[cs.Id()+"_"+string(cs.CredentialPurpose())] + assert.True(ok, "got unexpected credentialsource %v", cs) + assert.Equal(w.Id(), cs.Id()) + assert.Equal(w.CredentialPurpose(), cs.CredentialPurpose()) + assert.Equal(projTarget.PublicId, cs.TargetId()) } }) } @@ -402,7 +467,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { } type args struct { targetVersion uint32 - clIds []string + cls []*target.CredentialLibrary addToOrigLibs bool } tests := []struct { @@ -418,7 +483,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { setup: setupFn, args: args{ targetVersion: 2, - clIds: []string{}, + cls: []*target.CredentialLibrary{}, }, wantErr: false, wantAffectedRows: 10, @@ -428,7 +493,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { setup: setupFn, args: args{ targetVersion: 2, - clIds: []string{}, + cls: []*target.CredentialLibrary{}, addToOrigLibs: true, }, wantErr: false, @@ -439,7 +504,10 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { setup: setupFn, args: args{ targetVersion: 2, - clIds: []string{lib1.PublicId, lib2.PublicId}, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose), + }, addToOrigLibs: true, }, wantErr: false, @@ -450,7 +518,10 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { setup: setupFn, args: args{ targetVersion: 0, - clIds: []string{lib1.PublicId, lib2.PublicId}, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose), + }, addToOrigLibs: true, }, wantErr: true, @@ -461,7 +532,10 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { setup: setupFn, args: args{ targetVersion: 1000, - clIds: []string{lib1.PublicId, lib2.PublicId}, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose), + }, addToOrigLibs: true, }, wantErr: true, @@ -472,12 +546,39 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { setup: setupFn, args: args{ targetVersion: 2, - clIds: []string{lib1.PublicId, lib2.PublicId}, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose), + target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose), + }, addToOrigLibs: false, }, wantErr: false, wantAffectedRows: 12, }, + { + name: "egress-credential-purpose", + setup: setupFn, + args: args{ + targetVersion: 1, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose), + }, + }, + wantErr: true, + wantErrCode: errors.InvalidParameter, + }, + { + name: "ingress-credential-purpose", + setup: setupFn, + args: args{ + targetVersion: 1, + cls: []*target.CredentialLibrary{ + target.TestNewCredentialLibrary("", lib1.PublicId, credential.IngressPurpose), + }, + }, + wantErr: true, + wantErrCode: errors.InvalidParameter, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -491,16 +592,19 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { origCredSources, origCredLibraries = tt.setup(tar) } - cls := make([]*target.CredentialLibrary, 0, len(tt.args.clIds)) - for _, clid := range tt.args.clIds { - cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), clid, credential.ApplicationPurpose)) + 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, + } } - var wantIds []string - wantIds = append(wantIds, tt.args.clIds...) if tt.args.addToOrigLibs { - cls = append(cls, origCredLibraries...) + tt.args.cls = append(tt.args.cls, origCredLibraries...) for _, cl := range origCredLibraries { - wantIds = append(wantIds, cl.CredentialLibraryId) + wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = &target.TargetLibrary{ + CredentialLibrary: cl.CredentialLibrary, + } } } @@ -508,7 +612,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { require.NoError(err) assert.Equal(origCredSources, lookupCredSources) - _, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), tar.GetPublicId(), tt.args.targetVersion, cls) + _, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), tar.GetPublicId(), tt.args.targetVersion, tt.args.cls) if tt.wantErr { require.Error(err) assert.Equal(0, affectedRows) @@ -519,18 +623,14 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) { require.NoError(err) assert.Equal(tt.wantAffectedRows, affectedRows) - assert.Equal(len(wantIds), len(got)) - sort.Strings(wantIds) + assert.Equal(len(wantCredSources), len(got)) - var gotIds []string - if len(got) > 0 { - gotIds = make([]string, 0, len(got)) - for _, s := range got { - gotIds = append(gotIds, s.Id()) - } + for _, cs := range got { + w, ok := wantCredSources[cs.Id()+"_"+string(cs.CredentialPurpose())] + assert.True(ok, "got unexpected credentialsource %v", cs) + assert.Equal(w.Id(), cs.Id()) + assert.Equal(w.CredentialPurpose(), cs.CredentialPurpose()) } - sort.Strings(gotIds) - assert.Equal(wantIds, gotIds) foundTarget, _, _, err := repo.LookupTarget(context.Background(), tar.GetPublicId()) require.NoError(err) From 36f1ae75f714efc3091e28714cb18e9a9148f298 Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Thu, 28 Oct 2021 14:24:40 -0400 Subject: [PATCH 05/15] feat(sdk): Add support for egress credentials to target service --- globals/fields.go | 2 + .../api/services/target_service.pb.go | 628 +++++++++--------- .../api/resources/targets/v1/target.proto | 9 +- .../api/services/v1/target_service.proto | 8 +- .../handlers/targets/target_service.go | 52 +- .../api/resources/targets/target.pb.go | 229 ++++--- 6 files changed, 509 insertions(+), 419 deletions(-) diff --git a/globals/fields.go b/globals/fields.go index 692c8ddb9..c6a90108e 100644 --- a/globals/fields.go +++ b/globals/fields.go @@ -58,4 +58,6 @@ const ( ApplicationCredentialLibrariesField = "application_credential_libraries" ApplicationCredentialSourceIdsField = "application_credential_source_ids" ApplicationCredentialSourcesField = "application_credential_sources" + EgressCredentialSourceIdsField = "egress_credential_source_ids" + EgressCredentialSourcesField = "egress_credential_sources" ) diff --git a/internal/gen/controller/api/services/target_service.pb.go b/internal/gen/controller/api/services/target_service.pb.go index c6a919623..65620ce83 100644 --- a/internal/gen/controller/api/services/target_service.pb.go +++ b/internal/gen/controller/api/services/target_service.pb.go @@ -1546,6 +1546,7 @@ type AddTargetCredentialSourcesRequest struct { // The mutation will fail if the version does not match the latest known good version. Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` ApplicationCredentialSourceIds []string `protobuf:"bytes,3,rep,name=application_credential_source_ids,proto3" json:"application_credential_source_ids,omitempty"` + EgressCredentialSourceIds []string `protobuf:"bytes,4,rep,name=egress_credential_source_ids,proto3" json:"egress_credential_source_ids,omitempty"` } func (x *AddTargetCredentialSourcesRequest) Reset() { @@ -1601,6 +1602,13 @@ func (x *AddTargetCredentialSourcesRequest) GetApplicationCredentialSourceIds() return nil } +func (x *AddTargetCredentialSourcesRequest) GetEgressCredentialSourceIds() []string { + if x != nil { + return x.EgressCredentialSourceIds + } + return nil +} + type AddTargetCredentialSourcesResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1648,9 +1656,8 @@ func (x *AddTargetCredentialSourcesResponse) GetItem() *targets.Target { return nil } -// Sets the values for application_credential_source_ids. If any -// credential_source_id field that is not set in the request will result in -// those fields being cleared. +// Sets the values for credential sources. Any credential_source_id field that +// is not set in the request will result in those fields being cleared. type SetTargetCredentialSourcesRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1661,6 +1668,7 @@ type SetTargetCredentialSourcesRequest struct { // The mutation will fail if the version does not match the latest known good version. Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` ApplicationCredentialSourceIds []string `protobuf:"bytes,3,rep,name=application_credential_source_ids,proto3" json:"application_credential_source_ids,omitempty"` + EgressCredentialSourceIds []string `protobuf:"bytes,4,rep,name=egress_credential_source_ids,proto3" json:"egress_credential_source_ids,omitempty"` } func (x *SetTargetCredentialSourcesRequest) Reset() { @@ -1716,6 +1724,13 @@ func (x *SetTargetCredentialSourcesRequest) GetApplicationCredentialSourceIds() return nil } +func (x *SetTargetCredentialSourcesRequest) GetEgressCredentialSourceIds() []string { + if x != nil { + return x.EgressCredentialSourceIds + } + return nil +} + type SetTargetCredentialSourcesResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1773,6 +1788,7 @@ type RemoveTargetCredentialSourcesRequest struct { // The mutation will fail if the version does not match the latest known good version. Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` ApplicationCredentialSourceIds []string `protobuf:"bytes,3,rep,name=application_credential_source_ids,json=application_credential_source_id,proto3" json:"application_credential_source_ids,omitempty"` + EgressCredentialSourceIds []string `protobuf:"bytes,4,rep,name=egress_credential_source_ids,proto3" json:"egress_credential_source_ids,omitempty"` } func (x *RemoveTargetCredentialSourcesRequest) Reset() { @@ -1828,6 +1844,13 @@ func (x *RemoveTargetCredentialSourcesRequest) GetApplicationCredentialSourceIds return nil } +func (x *RemoveTargetCredentialSourcesRequest) GetEgressCredentialSourceIds() []string { + if x != nil { + return x.EgressCredentialSourceIds + } + return nil +} + type RemoveTargetCredentialSourcesResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2204,7 +2227,7 @@ var file_controller_api_services_v1_target_service_proto_rawDesc = []byte{ 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x04, 0x69, - 0x74, 0x65, 0x6d, 0x22, 0x9b, 0x01, 0x0a, 0x21, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x65, 0x6d, 0x22, 0xdf, 0x01, 0x0a, 0x21, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, @@ -2214,325 +2237,338 @@ var file_controller_api_services_v1_target_service_proto_rawDesc = []byte{ 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x21, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x73, 0x22, 0x65, 0x0a, 0x22, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x9b, 0x01, 0x0a, 0x21, 0x53, 0x65, 0x74, + 0x73, 0x12, 0x42, 0x0a, 0x1c, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x1c, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, + 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x73, 0x22, 0x65, 0x0a, 0x22, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x04, 0x69, + 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xdf, 0x01, 0x0a, + 0x21, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4c, 0x0a, 0x21, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x21, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x12, 0x42, 0x0a, 0x1c, 0x65, 0x67, + 0x72, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x1c, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x22, 0x65, + 0x0a, 0x22, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xe1, 0x01, 0x0a, 0x24, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4c, 0x0a, 0x21, 0x61, 0x70, 0x70, 0x6c, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x21, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x21, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x03, 0x28, 0x09, 0x52, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x22, 0x65, 0x0a, 0x22, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x04, - 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x9d, 0x01, - 0x0a, 0x24, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x4b, 0x0a, 0x21, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x12, 0x42, 0x0a, 0x1c, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x20, 0x61, 0x70, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x22, 0x68, 0x0a, - 0x25, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, - 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x91, 0x01, 0x0a, 0x17, 0x41, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, - 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x22, 0x69, 0x0a, 0x18, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x32, 0x97, 0x20, 0x0a, 0x0d, 0x54, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xa2, 0x01, 0x0a, 0x09, 0x47, 0x65, 0x74, - 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, - 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x38, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x10, 0x2f, 0x76, 0x31, - 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, - 0x74, 0x65, 0x6d, 0x92, 0x41, 0x17, 0x12, 0x15, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, - 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0x9a, 0x01, - 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x12, 0x2e, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x73, 0x92, 0x41, 0x14, 0x12, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6c, - 0x6c, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x12, 0xaf, 0x01, 0x0a, 0x0c, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2f, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3c, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x73, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, - 0x41, 0x1a, 0x12, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, - 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xad, 0x01, 0x0a, - 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2f, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x3a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x32, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, - 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x13, 0x12, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x73, 0x20, 0x61, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xa1, 0x01, 0x0a, - 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2f, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x2a, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x92, 0x41, 0x13, 0x12, 0x11, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, - 0x12, 0xcc, 0x01, 0x0a, 0x10, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, - 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x4d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x22, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x2d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x01, 0x2a, 0x62, - 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x17, 0x12, 0x15, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x7a, 0x65, 0x73, 0x20, 0x61, 0x20, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x12, - 0xda, 0x01, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, - 0x74, 0x53, 0x65, 0x74, 0x73, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, - 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x58, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x22, 0x1e, 0x2f, 0x76, 0x31, 0x2f, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x64, 0x64, - 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, 0x65, 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, - 0x74, 0x65, 0x6d, 0x92, 0x41, 0x26, 0x12, 0x24, 0x41, 0x64, 0x64, 0x73, 0x20, 0x65, 0x78, 0x69, - 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, 0x65, 0x74, 0x73, 0x20, - 0x74, 0x6f, 0x20, 0x61, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xd7, 0x01, 0x0a, - 0x11, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, - 0x74, 0x73, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x1c, 0x65, 0x67, 0x72, + 0x65, 0x73, 0x73, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x22, 0x68, 0x0a, 0x25, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x04, 0x69, + 0x74, 0x65, 0x6d, 0x22, 0x91, 0x01, 0x0a, 0x17, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, + 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x1d, + 0x0a, 0x0a, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x22, 0x69, 0x0a, 0x18, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x69, 0x74, + 0x65, 0x6d, 0x32, 0x97, 0x20, 0x0a, 0x0d, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0xa2, 0x01, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x12, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x47, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x38, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, + 0x41, 0x17, 0x12, 0x15, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, + 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0x9a, 0x01, 0x0a, 0x0b, 0x4c, 0x69, + 0x73, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x0d, 0x12, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x92, + 0x41, 0x14, 0x12, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x54, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x12, 0xaf, 0x01, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, - 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x55, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x22, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d, 0x68, 0x6f, - 0x73, 0x74, 0x2d, 0x73, 0x65, 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, - 0x92, 0x41, 0x23, 0x12, 0x21, 0x53, 0x65, 0x74, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x6f, - 0x73, 0x74, 0x20, 0x53, 0x65, 0x74, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xe4, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f, 0x76, - 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x12, - 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x59, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, 0x65, 0x74, 0x73, 0x3a, 0x01, 0x2a, - 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x24, 0x12, 0x22, 0x52, 0x65, 0x6d, 0x6f, 0x76, - 0x65, 0x73, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, 0x65, 0x74, 0x73, 0x20, 0x66, 0x72, 0x6f, - 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xe9, 0x01, - 0x0a, 0x14, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3c, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x19, 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x3a, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x1a, 0x12, 0x18, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, + 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xad, 0x01, 0x0a, 0x0c, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1e, 0x32, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, + 0x65, 0x6d, 0x92, 0x41, 0x13, 0x12, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, + 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xa1, 0x01, 0x0a, 0x0c, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x12, 0x2a, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x92, 0x41, 0x13, 0x12, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x73, 0x20, 0x61, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xcc, 0x01, 0x0a, + 0x10, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, - 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, - 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5e, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x2c, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, - 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x64, 0x64, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x29, - 0x12, 0x27, 0x41, 0x64, 0x64, 0x73, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, - 0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, - 0x61, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xe9, 0x01, 0x0a, 0x14, 0x53, 0x65, - 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4d, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x2d, 0x22, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, + 0x2d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, + 0x6d, 0x92, 0x41, 0x17, 0x12, 0x15, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x73, + 0x20, 0x61, 0x20, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x12, 0xda, 0x01, 0x0a, 0x11, + 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, + 0x73, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, + 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x58, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x22, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x64, 0x64, 0x2d, 0x68, 0x6f, 0x73, + 0x74, 0x2d, 0x73, 0x65, 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, + 0x41, 0x26, 0x12, 0x24, 0x41, 0x64, 0x64, 0x73, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, + 0x67, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, 0x65, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, + 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xd7, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x74, + 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x12, 0x34, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, + 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x55, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x29, 0x22, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, + 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, + 0x65, 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x23, 0x12, + 0x21, 0x53, 0x65, 0x74, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, + 0x65, 0x74, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x2e, 0x12, 0xe4, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x12, 0x37, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, + 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x59, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x2d, + 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, 0x65, 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, + 0x65, 0x6d, 0x92, 0x41, 0x24, 0x12, 0x22, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x48, + 0x6f, 0x73, 0x74, 0x20, 0x53, 0x65, 0x74, 0x73, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xe9, 0x01, 0x0a, 0x14, 0x41, 0x64, + 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, + 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, - 0x73, 0x65, 0x74, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x29, 0x12, 0x27, 0x53, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xf3, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, - 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, + 0x61, 0x64, 0x64, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x29, 0x12, 0x27, 0x41, 0x64, + 0x64, 0x73, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x48, 0x6f, 0x73, 0x74, + 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x54, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0xe9, 0x01, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x37, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, + 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x5e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d, + 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x29, 0x12, 0x27, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x2e, 0x12, 0xf3, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x2f, 0x22, 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, - 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x2d, 0x68, 0x6f, 0x73, 0x74, - 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, - 0x6d, 0x92, 0x41, 0x27, 0x12, 0x25, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x48, 0x6f, - 0x73, 0x74, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0x98, 0x02, 0x0a, 0x1c, - 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x3f, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, - 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x40, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, - 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x75, 0x88, 0x02, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x22, 0x29, 0x2f, 0x76, 0x31, 0x2f, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x64, 0x64, - 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x6c, 0x69, 0x62, 0x72, - 0x61, 0x72, 0x69, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, - 0x35, 0x12, 0x33, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x3a, 0x20, 0x75, - 0x73, 0x65, 0x20, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x69, 0x6e, - 0x73, 0x74, 0x65, 0x61, 0x64, 0x2e, 0x12, 0x98, 0x02, 0x0a, 0x1c, 0x53, 0x65, 0x74, 0x54, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, - 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x3f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x40, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x22, 0x24, + 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, + 0x3a, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x27, + 0x12, 0x25, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0x98, 0x02, 0x0a, 0x1c, 0x41, 0x64, 0x64, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, + 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x3f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, + 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x75, 0x88, 0x02, 0x01, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x22, 0x29, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d, 0x63, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, - 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x35, 0x12, 0x33, 0x44, 0x65, - 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x3a, 0x20, 0x75, 0x73, 0x65, 0x20, 0x53, 0x65, - 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, 0x61, 0x64, - 0x2e, 0x12, 0xa7, 0x02, 0x0a, 0x1f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, - 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x42, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x40, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x75, 0x88, 0x02, 0x01, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x22, 0x29, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x64, 0x64, 0x2d, 0x63, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, + 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x35, 0x12, 0x33, 0x44, + 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x3a, 0x20, 0x75, 0x73, 0x65, 0x20, 0x41, + 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, 0x61, + 0x64, 0x2e, 0x12, 0x98, 0x02, 0x0a, 0x1c, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, + 0x69, 0x65, 0x73, 0x12, 0x3f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x40, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x75, 0x88, 0x02, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x34, 0x22, 0x29, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, + 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x35, 0x12, 0x33, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, + 0x61, 0x74, 0x65, 0x64, 0x3a, 0x20, 0x75, 0x73, 0x65, 0x20, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, 0x61, 0x64, 0x2e, 0x12, 0xa7, 0x02, + 0x0a, 0x1f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, + 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, + 0x73, 0x12, 0x42, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x43, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x43, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, - 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x7b, - 0x88, 0x02, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x37, 0x22, 0x2c, 0x2f, 0x76, 0x31, 0x2f, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x6c, 0x69, - 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, - 0x92, 0x41, 0x38, 0x12, 0x36, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x3a, - 0x20, 0x75, 0x73, 0x65, 0x20, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, 0x61, 0x64, 0x2e, 0x12, 0x87, 0x02, 0x0a, 0x1a, - 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x7b, 0x88, 0x02, 0x01, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x37, 0x22, 0x2c, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x2d, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, + 0x69, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x38, 0x12, + 0x36, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x3a, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x69, + 0x6e, 0x73, 0x74, 0x65, 0x61, 0x64, 0x2e, 0x12, 0x87, 0x02, 0x0a, 0x1a, 0x41, 0x64, 0x64, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x22, 0x27, 0x2f, + 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, + 0x61, 0x64, 0x64, 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, + 0x41, 0x2f, 0x12, 0x2d, 0x41, 0x64, 0x64, 0x73, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, + 0x67, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x2e, 0x12, 0x84, 0x02, 0x0a, 0x1a, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x12, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, + 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x3e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, + 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x67, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x22, 0x27, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d, 0x63, 0x72, + 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x2c, 0x12, 0x2a, 0x53, 0x65, + 0x74, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0x91, 0x02, 0x0a, 0x1d, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x40, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6a, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x32, 0x22, 0x27, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, - 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x64, 0x64, 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, - 0x74, 0x65, 0x6d, 0x92, 0x41, 0x2f, 0x12, 0x2d, 0x41, 0x64, 0x64, 0x73, 0x20, 0x65, 0x78, 0x69, - 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x54, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0x84, 0x02, 0x0a, 0x1a, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x12, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, - 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x67, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x22, 0x27, 0x2f, 0x76, 0x31, - 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, - 0x74, 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x2c, - 0x12, 0x2a, 0x53, 0x65, 0x74, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x6f, 0x6e, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x12, 0x91, 0x02, 0x0a, - 0x1d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x40, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x41, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x6b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x35, 0x22, 0x2a, 0x2f, 0x76, 0x31, - 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, - 0x92, 0x41, 0x2d, 0x12, 0x2b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x43, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, - 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, - 0x42, 0x4d, 0x5a, 0x4b, 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, 0x67, 0x65, 0x6e, 0x2f, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x41, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x6b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x35, 0x22, 0x2a, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x2d, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x2d, 0x12, + 0x2b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x42, 0x4d, 0x5a, 0x4b, + 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, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/internal/proto/local/controller/api/resources/targets/v1/target.proto b/internal/proto/local/controller/api/resources/targets/v1/target.proto index 368995f3f..d52173522 100644 --- a/internal/proto/local/controller/api/resources/targets/v1/target.proto +++ b/internal/proto/local/controller/api/resources/targets/v1/target.proto @@ -143,11 +143,10 @@ message Target { // Output only. The application credential sources associated with this Target. repeated CredentialSource application_credential_sources = 410 [json_name="application_credential_sources"]; - // TODO: Uncomment when we suport more purposes beyond application -// // Output only. The egress credential libraries associated with this Target. -// repeated CredentialLibrary egress_credential_libraries = 190 [json_name="egress_credential_libraries"]; -// // Output only. The credential libraries associated with this Target. -// repeated CredentialLibrary ingress_credential_libraries = 200 [json_name="ingress_credential_libraries"]; + // Output only. The IDs of the egress credential source ids associated with this Target. + repeated string egress_credential_source_ids = 500 [json_name="egress_credential_source_ids"]; + // Output only. The egress credential sources associated with this Target. + repeated CredentialSource egress_credential_sources = 510 [json_name="egress_credential_sources"]; // The attributes that are applicable for the specific Target. google.protobuf.Struct attributes = 200 [(custom_options.v1.generate_sdk_option) = true]; diff --git a/internal/proto/local/controller/api/services/v1/target_service.proto b/internal/proto/local/controller/api/services/v1/target_service.proto index c0f61474a..22f6d27d1 100644 --- a/internal/proto/local/controller/api/services/v1/target_service.proto +++ b/internal/proto/local/controller/api/services/v1/target_service.proto @@ -475,21 +475,22 @@ message AddTargetCredentialSourcesRequest { // The mutation will fail if the version does not match the latest known good version. uint32 version = 2; repeated string application_credential_source_ids = 3 [json_name="application_credential_source_ids"]; + repeated string egress_credential_source_ids = 4 [json_name="egress_credential_source_ids"]; } message AddTargetCredentialSourcesResponse { api.resources.targets.v1.Target item = 1; } -// Sets the values for application_credential_source_ids. If any -// credential_source_id field that is not set in the request will result in -// those fields being cleared. +// Sets the values for credential sources. Any credential_source_id field that +// is not set in the request will result in those fields being cleared. message SetTargetCredentialSourcesRequest { string id = 1; // Version is used to ensure this resource has not changed. // The mutation will fail if the version does not match the latest known good version. uint32 version = 2; repeated string application_credential_source_ids = 3 [json_name="application_credential_source_ids"]; + repeated string egress_credential_source_ids = 4 [json_name="egress_credential_source_ids"]; } message SetTargetCredentialSourcesResponse { @@ -502,6 +503,7 @@ message RemoveTargetCredentialSourcesRequest { // The mutation will fail if the version does not match the latest known good version. uint32 version = 2; repeated string application_credential_source_ids = 3 [json_name="application_credential_source_id"]; + repeated string egress_credential_source_ids = 4 [json_name="egress_credential_source_ids"]; } message RemoveTargetCredentialSourcesResponse { diff --git a/internal/servers/controller/handlers/targets/target_service.go b/internal/servers/controller/handlers/targets/target_service.go index 4c9f9eb1b..0cb56b84e 100644 --- a/internal/servers/controller/handlers/targets/target_service.go +++ b/internal/servers/controller/handlers/targets/target_service.go @@ -584,7 +584,7 @@ func (s Service) AddTargetCredentialLibraries(ctx context.Context, req *pbs.AddT if authResults.Error != nil { return nil, authResults.Error } - t, ts, cl, err := s.addCredentialSourcesInRepo(ctx, req.GetId(), req.GetApplicationCredentialLibraryIds(), req.GetVersion()) + t, ts, cl, err := s.addCredentialSourcesInRepo(ctx, req.GetId(), req.GetApplicationCredentialLibraryIds(), nil, req.GetVersion()) if err != nil { return nil, err } @@ -622,7 +622,7 @@ func (s Service) SetTargetCredentialLibraries(ctx context.Context, req *pbs.SetT if authResults.Error != nil { return nil, authResults.Error } - t, ts, cl, err := s.setCredentialSourcesInRepo(ctx, req.GetId(), req.GetApplicationCredentialLibraryIds(), req.GetVersion()) + t, ts, cl, err := s.setCredentialSourcesInRepo(ctx, req.GetId(), req.GetApplicationCredentialLibraryIds(), nil, req.GetVersion()) if err != nil { return nil, err } @@ -660,7 +660,7 @@ func (s Service) RemoveTargetCredentialLibraries(ctx context.Context, req *pbs.R if authResults.Error != nil { return nil, authResults.Error } - t, ts, cl, err := s.removeCredentialSourcesInRepo(ctx, req.GetId(), req.GetApplicationCredentialLibraryIds(), req.GetVersion()) + t, ts, cl, err := s.removeCredentialSourcesInRepo(ctx, req.GetId(), req.GetApplicationCredentialLibraryIds(), nil, req.GetVersion()) if err != nil { return nil, err } @@ -698,7 +698,7 @@ func (s Service) AddTargetCredentialSources(ctx context.Context, req *pbs.AddTar if authResults.Error != nil { return nil, authResults.Error } - t, ts, cl, err := s.addCredentialSourcesInRepo(ctx, req.GetId(), req.GetApplicationCredentialSourceIds(), req.GetVersion()) + t, ts, cl, err := s.addCredentialSourcesInRepo(ctx, req.GetId(), req.GetApplicationCredentialSourceIds(), req.GetEgressCredentialSourceIds(), req.GetVersion()) if err != nil { return nil, err } @@ -736,7 +736,7 @@ func (s Service) SetTargetCredentialSources(ctx context.Context, req *pbs.SetTar if authResults.Error != nil { return nil, authResults.Error } - t, ts, cl, err := s.setCredentialSourcesInRepo(ctx, req.GetId(), req.GetApplicationCredentialSourceIds(), req.GetVersion()) + t, ts, cl, err := s.setCredentialSourcesInRepo(ctx, req.GetId(), req.GetApplicationCredentialSourceIds(), req.GetEgressCredentialSourceIds(), req.GetVersion()) if err != nil { return nil, err } @@ -774,7 +774,7 @@ func (s Service) RemoveTargetCredentialSources(ctx context.Context, req *pbs.Rem if authResults.Error != nil { return nil, authResults.Error } - t, ts, cl, err := s.removeCredentialSourcesInRepo(ctx, req.GetId(), req.GetApplicationCredentialSourceIds(), req.GetVersion()) + t, ts, cl, err := s.removeCredentialSourcesInRepo(ctx, req.GetId(), req.GetApplicationCredentialSourceIds(), req.GetEgressCredentialSourceIds(), req.GetVersion()) if err != nil { return nil, err } @@ -1346,12 +1346,12 @@ func (s Service) removeHostSourcesInRepo(ctx context.Context, targetId string, h return out, hs, cl, nil } -func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) { +func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, egressIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) { repo, err := s.repoFn() if err != nil { return nil, nil, nil, err } - credLibs, err := createCredLibs(targetId, applicationIds, nil, nil) + credLibs, err := createCredLibs(targetId, applicationIds, egressIds, nil) if err != nil { return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err) } @@ -1367,14 +1367,14 @@ func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string return out, hs, credSources, nil } -func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) { +func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, egressIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) { const op = "targets.(Service).setCredentialSourcesInRepo" repo, err := s.repoFn() if err != nil { return nil, nil, nil, err } - credLibs, err := createCredLibs(targetId, applicationIds, nil, nil) + credLibs, err := createCredLibs(targetId, applicationIds, egressIds, nil) if err != nil { return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err) } @@ -1395,14 +1395,14 @@ func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string return out, hs, credSources, nil } -func (s Service) removeCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) { +func (s Service) removeCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, egressIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) { const op = "targets.(Service).removeCredentialSourcesInRepo" repo, err := s.repoFn() if err != nil { return nil, nil, nil, err } - credLibs, err := createCredLibs(targetId, applicationIds, nil, nil) + credLibs, err := createCredLibs(targetId, applicationIds, egressIds, nil) if err != nil { return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err) } @@ -1921,8 +1921,9 @@ func validateAddCredentialSourcesRequest(req *pbs.AddTargetCredentialSourcesRequ if req.GetVersion() == 0 { badFields[globals.VersionField] = "Required field." } - if len(req.GetApplicationCredentialSourceIds()) == 0 { - badFields[globals.ApplicationCredentialSourceIdsField] = "Must be non-empty." + if len(req.GetApplicationCredentialSourceIds())+len(req.GetEgressCredentialSourceIds()) == 0 { + badFields[globals.ApplicationCredentialSourceIdsField] = "Application or Egress Credential Source IDs must be provided." + 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) { @@ -1930,6 +1931,12 @@ func validateAddCredentialSourcesRequest(req *pbs.AddTargetCredentialSourcesRequ break } } + for _, cl := range req.GetEgressCredentialSourceIds() { + if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix) { + badFields[globals.EgressCredentialSourceIdsField] = fmt.Sprintf("Incorrectly formatted credential source identifier %q.", cl) + break + } + } if len(badFields) > 0 { return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields) } @@ -1950,6 +1957,12 @@ func validateSetCredentialSourcesRequest(req *pbs.SetTargetCredentialSourcesRequ break } } + for _, cl := range req.GetEgressCredentialSourceIds() { + if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix) { + badFields[globals.EgressCredentialSourceIdsField] = fmt.Sprintf("Incorrectly formatted credential source identifier %q.", cl) + break + } + } if len(badFields) > 0 { return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields) } @@ -1964,8 +1977,9 @@ func validateRemoveCredentialSourcesRequest(req *pbs.RemoveTargetCredentialSourc if req.GetVersion() == 0 { badFields[globals.VersionField] = "Required field." } - if len(req.GetApplicationCredentialSourceIds()) == 0 { - badFields[globals.ApplicationCredentialLibraryIdsField] = "Must be non-empty." + if len(req.GetApplicationCredentialSourceIds())+len(req.GetEgressCredentialSourceIds()) == 0 { + badFields[globals.ApplicationCredentialSourceIdsField] = "Application or Egress Credential Source IDs must be provided." + 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) { @@ -1973,6 +1987,12 @@ func validateRemoveCredentialSourcesRequest(req *pbs.RemoveTargetCredentialSourc break } } + for _, cl := range req.GetEgressCredentialSourceIds() { + if !handlers.ValidId(handlers.Id(cl), vault.CredentialLibraryPrefix) { + badFields[globals.EgressCredentialSourceIdsField] = fmt.Sprintf("Incorrectly formatted credential source identifier %q.", cl) + break + } + } if len(badFields) > 0 { return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields) } diff --git a/sdk/pbs/controller/api/resources/targets/target.pb.go b/sdk/pbs/controller/api/resources/targets/target.pb.go index cf0c3a283..388432916 100644 --- a/sdk/pbs/controller/api/resources/targets/target.pb.go +++ b/sdk/pbs/controller/api/resources/targets/target.pb.go @@ -487,6 +487,10 @@ type Target struct { ApplicationCredentialSourceIds []string `protobuf:"bytes,400,rep,name=application_credential_source_ids,proto3" json:"application_credential_source_ids,omitempty"` // Output only. The application credential sources associated with this Target. ApplicationCredentialSources []*CredentialSource `protobuf:"bytes,410,rep,name=application_credential_sources,proto3" json:"application_credential_sources,omitempty"` + // Output only. The IDs of the egress credential source ids associated with this Target. + EgressCredentialSourceIds []string `protobuf:"bytes,500,rep,name=egress_credential_source_ids,proto3" json:"egress_credential_source_ids,omitempty"` + // Output only. The egress credential sources associated with this Target. + EgressCredentialSources []*CredentialSource `protobuf:"bytes,510,rep,name=egress_credential_sources,proto3" json:"egress_credential_sources,omitempty"` // The attributes that are applicable for the specific Target. Attributes *structpb.Struct `protobuf:"bytes,200,opt,name=attributes,proto3" json:"attributes,omitempty"` // Output only. The available actions on this resource for this user. @@ -667,6 +671,20 @@ func (x *Target) GetApplicationCredentialSources() []*CredentialSource { return nil } +func (x *Target) GetEgressCredentialSourceIds() []string { + if x != nil { + return x.EgressCredentialSourceIds + } + return nil +} + +func (x *Target) GetEgressCredentialSources() []*CredentialSource { + if x != nil { + return x.EgressCredentialSources + } + return nil +} + func (x *Target) GetAttributes() *structpb.Struct { if x != nil { return x.Attributes @@ -1130,7 +1148,7 @@ var file_controller_api_resources_targets_v1_target_proto_rawDesc = []byte{ 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0xe9, 0x0c, 0x0a, 0x06, 0x54, 0x61, + 0x74, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0xa4, 0x0e, 0x0a, 0x06, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, @@ -1226,92 +1244,104 @@ var file_controller_api_resources_targets_v1_target_proto_rawDesc = []byte{ 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x1e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x73, 0x18, 0xc8, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, - 0x63, 0x74, 0x42, 0x04, 0xa0, 0xda, 0x29, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, - 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xac, 0x02, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x87, 0x01, 0x0a, 0x13, 0x54, 0x63, 0x70, 0x54, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x70, 0x0a, - 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x42, 0x2e, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x26, 0x0a, 0x17, 0x61, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, - 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, - 0x74, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x22, - 0x26, 0x0a, 0x0a, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xed, 0x03, 0x0a, 0x18, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x44, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, - 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, - 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, - 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x63, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, - 0x5a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x78, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x70, 0x72, 0x69, - 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x82, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, - 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x8c, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x68, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x18, 0x8d, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x12, 0x52, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x6e, - 0x66, 0x6f, 0x18, 0x96, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, - 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0xeb, 0x03, 0x0a, 0x14, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x43, - 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, + 0x72, 0x63, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x1c, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0xf4, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x1c, 0x65, 0x67, 0x72, + 0x65, 0x73, 0x73, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x12, 0x74, 0x0a, 0x19, 0x65, 0x67, 0x72, + 0x65, 0x73, 0x73, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0xfe, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x73, 0x63, - 0x6f, 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x32, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x12, 0x20, 0x0a, - 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x3c, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x12, - 0x18, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x46, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x30, 0x0a, - 0x13, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x61, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, - 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x64, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x58, 0x0a, 0x0b, 0x63, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18, 0x6e, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x73, 0x42, 0x50, 0x5a, 0x4e, 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, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x62, 0x73, 0x2f, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x3b, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x19, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, + 0x3e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0xc8, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x04, 0xa0, + 0xda, 0x29, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, + 0x2f, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xac, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0x87, 0x01, 0x0a, 0x13, 0x54, 0x63, 0x70, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x70, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2e, 0xa0, 0xda, + 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x26, 0x0a, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x12, + 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x0c, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x26, 0x0a, 0x0a, 0x57, 0x6f, + 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x22, 0xed, 0x03, 0x0a, 0x18, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, + 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x12, + 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x43, 0x0a, + 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x73, 0x63, 0x6f, + 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, + 0x69, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x18, 0x78, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, + 0x6b, 0x65, 0x79, 0x18, 0x82, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x72, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x8c, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, + 0x64, 0x12, 0x1b, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x8d, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x52, + 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x96, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x6e, + 0x66, 0x6f, 0x22, 0xeb, 0x03, 0x0a, 0x14, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, + 0x70, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, + 0x6f, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x3e, + 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x28, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x32, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, + 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x68, + 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x6f, + 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x46, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x6f, 0x73, + 0x74, 0x5f, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x50, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x5a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x64, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x58, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18, 0x6e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, + 0x42, 0x50, 0x5a, 0x4e, 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, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x62, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x3b, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1363,19 +1393,20 @@ var file_controller_api_resources_targets_v1_target_proto_depIdxs = []int32{ 13, // 13: controller.api.resources.targets.v1.Target.worker_filter:type_name -> google.protobuf.StringValue 3, // 14: controller.api.resources.targets.v1.Target.application_credential_libraries:type_name -> controller.api.resources.targets.v1.CredentialLibrary 2, // 15: controller.api.resources.targets.v1.Target.application_credential_sources:type_name -> controller.api.resources.targets.v1.CredentialSource - 11, // 16: controller.api.resources.targets.v1.Target.attributes:type_name -> google.protobuf.Struct - 15, // 17: controller.api.resources.targets.v1.TcpTargetAttributes.default_port:type_name -> google.protobuf.UInt32Value - 12, // 18: controller.api.resources.targets.v1.SessionAuthorizationData.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo - 14, // 19: controller.api.resources.targets.v1.SessionAuthorizationData.created_time:type_name -> google.protobuf.Timestamp - 8, // 20: controller.api.resources.targets.v1.SessionAuthorizationData.worker_info:type_name -> controller.api.resources.targets.v1.WorkerInfo - 12, // 21: controller.api.resources.targets.v1.SessionAuthorization.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo - 14, // 22: controller.api.resources.targets.v1.SessionAuthorization.created_time:type_name -> google.protobuf.Timestamp - 5, // 23: controller.api.resources.targets.v1.SessionAuthorization.credentials:type_name -> controller.api.resources.targets.v1.SessionCredential - 24, // [24:24] is the sub-list for method output_type - 24, // [24:24] is the sub-list for method input_type - 24, // [24:24] is the sub-list for extension type_name - 24, // [24:24] is the sub-list for extension extendee - 0, // [0:24] is the sub-list for field type_name + 2, // 16: controller.api.resources.targets.v1.Target.egress_credential_sources:type_name -> controller.api.resources.targets.v1.CredentialSource + 11, // 17: controller.api.resources.targets.v1.Target.attributes:type_name -> google.protobuf.Struct + 15, // 18: controller.api.resources.targets.v1.TcpTargetAttributes.default_port:type_name -> google.protobuf.UInt32Value + 12, // 19: controller.api.resources.targets.v1.SessionAuthorizationData.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo + 14, // 20: controller.api.resources.targets.v1.SessionAuthorizationData.created_time:type_name -> google.protobuf.Timestamp + 8, // 21: controller.api.resources.targets.v1.SessionAuthorizationData.worker_info:type_name -> controller.api.resources.targets.v1.WorkerInfo + 12, // 22: controller.api.resources.targets.v1.SessionAuthorization.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo + 14, // 23: controller.api.resources.targets.v1.SessionAuthorization.created_time:type_name -> google.protobuf.Timestamp + 5, // 24: controller.api.resources.targets.v1.SessionAuthorization.credentials:type_name -> controller.api.resources.targets.v1.SessionCredential + 25, // [25:25] is the sub-list for method output_type + 25, // [25:25] is the sub-list for method input_type + 25, // [25:25] is the sub-list for extension type_name + 25, // [25:25] is the sub-list for extension extendee + 0, // [0:25] is the sub-list for field type_name } func init() { file_controller_api_resources_targets_v1_target_proto_init() } From 1da403a2d2de9e25bb0595ca1c9147081a9e02e7 Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Thu, 28 Oct 2021 14:25:30 -0400 Subject: [PATCH 06/15] feat(api): Add support for egress credentials for targets endpoint --- api/targets/option.gen.go | 12 ++++++++++ api/targets/target.gen.go | 2 ++ internal/api/genapi/input.go | 5 ++++ internal/gen/controller.swagger.json | 36 +++++++++++++++++++++++++++- 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/api/targets/option.gen.go b/api/targets/option.gen.go index 11f0f82ab..5c47abf6d 100644 --- a/api/targets/option.gen.go +++ b/api/targets/option.gen.go @@ -159,6 +159,18 @@ func DefaultDescription() Option { } } +func WithEgressCredentialSourceIds(inEgressCredentialSourceIds []string) Option { + return func(o *options) { + o.postMap["egress_credential_source_ids"] = inEgressCredentialSourceIds + } +} + +func DefaultEgressCredentialSourceIds() Option { + return func(o *options) { + o.postMap["egress_credential_source_ids"] = nil + } +} + func WithHostId(inHostId string) Option { return func(o *options) { o.postMap["host_id"] = inHostId diff --git a/api/targets/target.gen.go b/api/targets/target.gen.go index 0c9cca148..1e1a64fc7 100644 --- a/api/targets/target.gen.go +++ b/api/targets/target.gen.go @@ -33,6 +33,8 @@ type Target struct { ApplicationCredentialLibraries []*CredentialLibrary `json:"application_credential_libraries,omitempty"` ApplicationCredentialSourceIds []string `json:"application_credential_source_ids,omitempty"` ApplicationCredentialSources []*CredentialSource `json:"application_credential_sources,omitempty"` + EgressCredentialSourceIds []string `json:"egress_credential_source_ids,omitempty"` + EgressCredentialSources []*CredentialSource `json:"egress_credential_sources,omitempty"` Attributes map[string]interface{} `json:"attributes,omitempty"` AuthorizedActions []string `json:"authorized_actions,omitempty"` diff --git a/internal/api/genapi/input.go b/internal/api/genapi/input.go index 0a3cba000..a3129014a 100644 --- a/internal/api/genapi/input.go +++ b/internal/api/genapi/input.go @@ -649,6 +649,11 @@ var inputStructs = []*structInfo{ ProtoName: "application_credential_source_ids", FieldType: "[]string", }, + { + Name: "EgressCredentialSourceIds", + ProtoName: "egress_credential_source_ids", + FieldType: "[]string", + }, }, versionEnabled: true, typeOnCreate: true, diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index ee2a1d62c..cfa71657b 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -2812,6 +2812,12 @@ "items": { "type": "string" } + }, + "egress_credential_source_ids": { + "type": "array", + "items": { + "type": "string" + } } } } @@ -3048,6 +3054,12 @@ "items": { "type": "string" } + }, + "egress_credential_source_ids": { + "type": "array", + "items": { + "type": "string" + } } } } @@ -3233,9 +3245,15 @@ "items": { "type": "string" } + }, + "egress_credential_source_ids": { + "type": "array", + "items": { + "type": "string" + } } }, - "description": "Sets the values for application_credential_source_ids. If any\ncredential_source_id field that is not set in the request will result in\nthose fields being cleared." + "description": "Sets the values for credential sources. Any credential_source_id field that\nis not set in the request will result in those fields being cleared." } } ], @@ -5054,6 +5072,22 @@ "description": "Output only. The application credential sources associated with this Target.", "readOnly": true }, + "egress_credential_source_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Output only. The IDs of the egress credential source ids associated with this Target.", + "readOnly": true + }, + "egress_credential_sources": { + "type": "array", + "items": { + "$ref": "#/definitions/controller.api.resources.targets.v1.CredentialSource" + }, + "description": "Output only. The egress credential sources associated with this Target.", + "readOnly": true + }, "attributes": { "type": "object", "description": "The attributes that are applicable for the specific Target." From 7d7d8af6947faed8887eb804c66794d80f4ae902 Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Thu, 28 Oct 2021 14:25:57 -0400 Subject: [PATCH 07/15] feat(cli): Add support for egress credentials for targets command --- internal/cmd/commands/targetscmd/funcs.go | 47 ++++++++++++++++++----- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/internal/cmd/commands/targetscmd/funcs.go b/internal/cmd/commands/targetscmd/funcs.go index 77cf8791f..8ffa0bb6c 100644 --- a/internal/cmd/commands/targetscmd/funcs.go +++ b/internal/cmd/commands/targetscmd/funcs.go @@ -33,6 +33,7 @@ type extraCmdVars struct { flagHostSources []string flagApplicationCredentialLibraries []string flagApplicationCredentialSources []string + flagEgressCredentialSources []string flagHostId string sar *targets.SessionAuthorizationResult } @@ -49,9 +50,9 @@ func extraActionsFlagsMapFuncImpl() map[string][]string { "add-credential-libraries": {"id", "application-credential-library", "version"}, "remove-credential-libraries": {"id", "application-credential-library", "version"}, "set-credential-libraries": {"id", "application-credential-library", "version"}, - "add-credential-sources": {"id", "application-credential-source", "version"}, - "remove-credential-sources": {"id", "application-credential-source", "version"}, - "set-credential-sources": {"id", "application-credential-source", "version"}, + "add-credential-sources": {"id", "application-credential-source", "egress-credential-source", "version"}, + "remove-credential-sources": {"id", "application-credential-source", "egress-credential-source", "version"}, + "set-credential-sources": {"id", "application-credential-source", "egress-credential-source", "version"}, } } @@ -361,6 +362,12 @@ func extraFlagsFuncImpl(c *Command, _ *base.FlagSets, f *base.FlagSet) { Target: &c.flagApplicationCredentialSources, Usage: "The credential source for application purpose to add, set, or remove. May be specified multiple times.", }) + case "egress-credential-source": + f.StringSliceVar(&base.StringSliceVar{ + Name: "egress-credential-source", + Target: &c.flagEgressCredentialSources, + Usage: "The credential source for egress purpose to add, set, or remove. May be specified multiple times.", + }) } } @@ -460,7 +467,6 @@ func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]targets.Op } case "add-credential-libraries", "remove-credential-libraries": - // TODO: As we add other purposes, add them to this check if len(c.flagApplicationCredentialLibraries) == 0 { c.UI.Error("No credential-libraries supplied via -application-credential-library") return false @@ -469,14 +475,19 @@ func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]targets.Op case "add-credential-sources", "remove-credential-sources": // TODO: As we add other purposes, add them to this check - if len(c.flagApplicationCredentialSources) == 0 { - c.UI.Error("No credential sources supplied via -application-credential-source") + if len(c.flagApplicationCredentialSources)+len(c.flagEgressCredentialSources) == 0 { + c.UI.Error("No credential sources supplied via -application-credential-source or -egress-credential-source") return false } - *opts = append(*opts, targets.WithApplicationCredentialSourceIds(c.flagApplicationCredentialSources)) + + if len(c.flagApplicationCredentialSources) > 0 { + *opts = append(*opts, targets.WithApplicationCredentialSourceIds(c.flagApplicationCredentialSources)) + } + if len(c.flagEgressCredentialSources) > 0 { + *opts = append(*opts, targets.WithEgressCredentialSourceIds(c.flagEgressCredentialSources)) + } case "set-credential-libraries": - // TODO: As we add other purposes, add them to this check switch len(c.flagApplicationCredentialLibraries) { case 0: c.UI.Error("No credential-libraries supplied via -application-credential-library") @@ -493,10 +504,14 @@ func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]targets.Op case "set-credential-sources": // TODO: As we add other purposes, add them to this check + if len(c.flagApplicationCredentialSources)+len(c.flagEgressCredentialSources) == 0 { + c.UI.Error("No credential sources supplied via -application-credential-source or -egress-credential-source") + return false + } + switch len(c.flagApplicationCredentialSources) { case 0: - c.UI.Error("No credential sources supplied via -application-credential-source") - return false + // do nothing case 1: if c.flagApplicationCredentialSources[0] == "null" { *opts = append(*opts, targets.DefaultApplicationCredentialSourceIds()) @@ -506,6 +521,18 @@ func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]targets.Op default: *opts = append(*opts, targets.WithApplicationCredentialSourceIds(c.flagApplicationCredentialSources)) } + switch len(c.flagEgressCredentialSources) { + case 0: + // do nothing + case 1: + if c.flagEgressCredentialSources[0] == "null" { + *opts = append(*opts, targets.DefaultEgressCredentialSourceIds()) + break + } + fallthrough + default: + *opts = append(*opts, targets.WithEgressCredentialSourceIds(c.flagEgressCredentialSources)) + } case "authorize-session": if len(c.flagHostId) != 0 { From decc3ec2cf5510ec80989c3a318b2fd4e2072935 Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Tue, 2 Nov 2021 15:38:37 -0400 Subject: [PATCH 08/15] test(targets): Change test to not depend on response order (#1653) This test started failing when the order of the list response changed. Since the order does not matter, this test was updated to not depend on the order. --- .../handlers/targets/target_service_test.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/internal/servers/controller/handlers/targets/target_service_test.go b/internal/servers/controller/handlers/targets/target_service_test.go index 8c77191df..e28ffb64a 100644 --- a/internal/servers/controller/handlers/targets/target_service_test.go +++ b/internal/servers/controller/handlers/targets/target_service_test.go @@ -288,7 +288,16 @@ func TestList(t *testing.T) { return } require.NoError(gErr) - assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "ListTargets(%q) scope %q, got response %q, wanted %q", tc.name, tc.req.GetScopeId(), got, tc.res) + assert.Equal(len(tc.res.Items), len(got.Items)) + wantById := make(map[string]*pb.Target, len(tc.res.Items)) + for _, t := range tc.res.Items { + wantById[t.Id] = t + } + for _, t := range got.Items { + want, ok := wantById[t.Id] + assert.True(ok, "Got unexpected target with id: %s", t.Id) + assert.Empty(cmp.Diff(t, want, protocmp.Transform()), "got %v, wanted %v", t, want) + } // Test with anon user got, gErr = s.ListTargets(auth.DisabledAuthTestContext(iamRepoFn, tc.req.GetScopeId(), auth.WithUserId(auth.AnonymousUserId)), tc.req) From 35a7c4f6e77cb9989a2bdfe05e6a1ee650f10e40 Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Thu, 21 Oct 2021 14:30:33 -0400 Subject: [PATCH 09/15] feat(dbtest): Make test container name configurable --- CONTRIBUTING.md | 9 +++++++++ testing/dbtest/docker/Makefile | 10 ++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9167495cc..5490871ab 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -144,6 +144,15 @@ $ make test-database-up $ make test ``` +By default the container name is `boundary-sql-tests`. +This can be changed in the same way as the port: + +``` +$ export TEST_CONTAINER_NAME="custom-name" +$ make test-database-up +$ docker logs custom-name +``` + The default docker image is built using the `postgres:11` base image. The image can be changed using a make option to test against other versions: diff --git a/testing/dbtest/docker/Makefile b/testing/dbtest/docker/Makefile index 93734b9f0..0d4ff3d99 100644 --- a/testing/dbtest/docker/Makefile +++ b/testing/dbtest/docker/Makefile @@ -8,6 +8,7 @@ IMAGE_NAME=postgres IMAGE_TAG ?= $(REGISTRY_NAME)/$(IMAGE_NAME):11-alpine PG_OPTS ?= TEST_DB_PORT ?= 5432 +TEST_CONTAINER_NAME ?= boundary-sql-tests # Generate targets from dockerfiles dockerfiles = $(wildcard Dockerfile.*) @@ -29,7 +30,7 @@ database-up: @echo "Additional postgres configuration: $(PG_OPTS)" @docker run \ $(DOCKER_ARGS) \ - --name boundary-sql-tests \ + --name $(TEST_CONTAINER_NAME) \ -p $(TEST_DB_PORT):5432 \ -e POSTGRES_PASSWORD=boundary \ -e POSTGRES_USER=boundary \ @@ -40,11 +41,12 @@ database-up: $(IMAGE_TAG) \ -c 'config_file=/etc/postgresql/postgresql.conf' \ $(PG_OPTS) 1> /dev/null + @echo "Container name: $(TEST_CONTAINER_NAME)" @echo "Test database available at: 127.0.0.1:$(TEST_DB_PORT)" @echo "For database logs run:" - @echo " docker logs boundary-sql-tests" + @echo " docker logs $(TEST_CONTAINER_NAME)" clean: - docker stop boundary-sql-tests || true - docker rm -v boundary-sql-tests || true + docker stop $(TEST_CONTAINER_NAME) || true + docker rm -v $(TEST_CONTAINER_NAME) || true .PHONY: all docker-build database-up ${docker-builds} ${docker-publishes} clean From 1a24a0fc2ff3bc7745c568715ebf33f2e9743405 Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Thu, 21 Oct 2021 14:35:02 -0400 Subject: [PATCH 10/15] feat(sqltest): Make container name configurable --- internal/db/sqltest/Makefile | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/internal/db/sqltest/Makefile b/internal/db/sqltest/Makefile index 04731bb21..a05dadd79 100644 --- a/internal/db/sqltest/Makefile +++ b/internal/db/sqltest/Makefile @@ -21,6 +21,8 @@ POSTGRES_DOCKER_IMAGE := $(POSTGRES_DOCKER_IMAGE_BASE):$(PG_DOCKER_TAG) PG_TAP_DOCKER_IMAGE_BASE ?= subzerocloud/pgtap PG_TAP_DOCKER_IMAGE := $(PG_TAP_DOCKER_IMAGE_BASE):$(PG_TAP_DOCKER_TAG) +SQL_TEST_CONTAINER_NAME ?= boundary-sql-tests + # re-write paths for docker dockerized_tests = $(patsubst tests/%,/test/%,$(TESTS)) @@ -29,7 +31,7 @@ test: @echo Using $(POSTGRES_DOCKER_IMAGE) @echo Using $(PG_TAP_DOCKER_IMAGE) @docker run -d \ - --name boundary-sql-tests \ + --name $(SQL_TEST_CONTAINER_NAME) \ -e POSTGRES_PASSWORD=boundary \ -e POSTGRES_USER=boundary \ -e POSTGRES_DB=boundary \ @@ -38,7 +40,7 @@ test: $(POSTGRES_DOCKER_IMAGE) @docker run -it --rm \ --name test \ - --link boundary-sql-tests:db \ + --link $(SQL_TEST_CONTAINER_NAME):db \ -e DATABASE=boundary \ -e HOST=db \ -e PORT=5432 \ @@ -47,12 +49,12 @@ test: -e TESTS="$(PROVE_OPTS) $(dockerized_tests)" \ -v "$(CWD)/tests":/test \ $(PG_TAP_DOCKER_IMAGE); \ - (ret=$$?; docker stop boundary-sql-tests &>/dev/null && docker rm -v boundary-sql-tests &>/dev/null && exit $$ret) + (ret=$$?; docker stop $(SQL_TEST_CONTAINER_NAME) &>/dev/null && docker rm -v $(SQL_TEST_CONTAINER_NAME) &>/dev/null && exit $$ret) database-up: @echo Using $(POSTGRES_DOCKER_IMAGE) @docker run -d \ - --name boundary-sql-tests \ + --name $(SQL_TEST_CONTAINER_NAME) \ -e POSTGRES_PASSWORD=boundary \ -e POSTGRES_USER=boundary \ -e POSTGRES_DB=boundary \ @@ -64,7 +66,7 @@ run-tests: @echo Using $(PG_TAP_DOCKER_IMAGE) @docker run -it --rm \ --name test \ - --link boundary-sql-tests:db \ + --link $(SQL_TEST_CONTAINER_NAME):db \ -e DATABASE=boundary \ -e HOST=db \ -e PORT=5432 \ @@ -75,7 +77,7 @@ run-tests: $(PG_TAP_DOCKER_IMAGE) clean: - docker stop boundary-sql-tests || true - docker rm -v boundary-sql-tests || true + docker stop $(SQL_TEST_CONTAINER_NAME) || true + docker rm -v $(SQL_TEST_CONTAINER_NAME) || true .PHONY: all clean test database-up run-tests From 8d3f666bba7f523513934cb4d1d5a8dfa325970e Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 3 Nov 2021 13:55:58 +0000 Subject: [PATCH 11/15] docs: include boundary-ui dependencies for make dev (#1657) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9cd43294e..f2685151e 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ for permanent installations, are detailed in our [Installation Guide](https://ww If you have the following requirements met locally: - Golang v1.16 or greater - Docker +- [Boundary UI Dependencies](https://github.com/hashicorp/boundary-ui#prerequisites) You can get up and running with Boundary quickly. Simply run: From 4df3b40defe0488212d90ea529e4e28a50fcd539 Mon Sep 17 00:00:00 2001 From: Jim Date: Wed, 3 Nov 2021 14:04:47 -0400 Subject: [PATCH 12/15] feature (db): Add support for multi-column PKs (#1658) --- internal/db/common/update.go | 18 +- internal/db/common/update_test.go | 18 ++ internal/db/db_test/db.go | 77 ++++++- internal/db/db_test/db_test.pb.go | 208 ++++++++++++++++-- internal/db/read_writer.go | 61 +++-- internal/db/read_writer_test.go | 101 ++++++++- .../migrations/oss/postgres/19/01_db.up.sql | 56 +++++ .../storage/db/db_test/v1/db_test.proto | 23 ++ internal/session/immutable_fields_test.go | 33 ++- 9 files changed, 526 insertions(+), 69 deletions(-) create mode 100644 internal/db/schema/migrations/oss/postgres/19/01_db.up.sql diff --git a/internal/db/common/update.go b/internal/db/common/update.go index 71b11e3fd..2a76a6f59 100644 --- a/internal/db/common/update.go +++ b/internal/db/common/update.go @@ -46,6 +46,16 @@ func UpdateFields(i interface{}, fieldMaskPaths []string, setToNullPaths []strin val := reflect.Indirect(reflect.ValueOf(i)) structTyp := val.Type() for i := 0; i < structTyp.NumField(); i++ { + if f, ok := maskPaths[strings.ToUpper(structTyp.Field(i).Name)]; ok { + updateFields[f] = val.Field(i).Interface() + found[strings.ToUpper(f)] = struct{}{} + continue + } + if f, ok := nullPaths[strings.ToUpper(structTyp.Field(i).Name)]; ok { + updateFields[f] = gorm.Expr("NULL") + found[strings.ToUpper(f)] = struct{}{} + continue + } kind := structTyp.Field(i).Type.Kind() if kind == reflect.Struct || kind == reflect.Ptr { embType := structTyp.Field(i).Type @@ -76,14 +86,6 @@ func UpdateFields(i interface{}, fieldMaskPaths []string, setToNullPaths []strin continue } } - if f, ok := maskPaths[strings.ToUpper(structTyp.Field(i).Name)]; ok { - updateFields[f] = val.Field(i).Interface() - found[strings.ToUpper(f)] = struct{}{} - } - if f, ok := nullPaths[strings.ToUpper(structTyp.Field(i).Name)]; ok { - updateFields[f] = gorm.Expr("NULL") - found[strings.ToUpper(f)] = struct{}{} - } } if missing := findMissingPaths(setToNullPaths, found); len(missing) != 0 { diff --git a/internal/db/common/update_test.go b/internal/db/common/update_test.go index 4da3a16c6..22893f06e 100644 --- a/internal/db/common/update_test.go +++ b/internal/db/common/update_test.go @@ -4,9 +4,13 @@ import ( "testing" "github.com/hashicorp/boundary/internal/db/db_test" + "github.com/hashicorp/boundary/internal/db/timestamp" "github.com/hashicorp/go-secure-stdlib/base62" "github.com/hashicorp/go-uuid" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" "gorm.io/gorm" ) @@ -398,6 +402,20 @@ func TestUpdateFields(t *testing.T) { assert.Equal(tt.want, got) }) } + t.Run("valid-embedded-timestamp", func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + wantTs := ×tamp.Timestamp{ + Timestamp: ×tamppb.Timestamp{ + Seconds: 1, + Nanos: 1, + }, + } + u := testUser(t, "", "") + u.UpdateTime = wantTs + got, err := UpdateFields(u, []string{"UpdateTime"}, nil) + require.NoError(err) + assert.True(proto.Equal(wantTs, got["UpdateTime"].(*timestamp.Timestamp))) + }) } func testUser(t *testing.T, name, email string) *db_test.TestUser { diff --git a/internal/db/db_test/db.go b/internal/db/db_test/db.go index 0d641b2a1..12218629a 100644 --- a/internal/db/db_test/db.go +++ b/internal/db/db_test/db.go @@ -2,15 +2,19 @@ package db_test import ( + "errors" + "github.com/hashicorp/go-secure-stdlib/base62" "google.golang.org/protobuf/proto" ) const ( - defaultUserTablename = "db_test_user" - defaultCarTableName = "db_test_car" - defaultRentalTableName = "db_test_rental" - defaultScooterTableName = "db_test_scooter" + defaultUserTablename = "db_test_user" + defaultCarTableName = "db_test_car" + defaultRentalTableName = "db_test_rental" + defaultScooterTableName = "db_test_scooter" + defaultAccessoryTableName = "db_test_accessory" + defaultScooterAccessoryTableName = "db_test_scooter_accessory" ) type TestUser struct { @@ -153,6 +157,71 @@ func (t *TestScooter) SetTableName(name string) { t.table = name } +type TestAccessory struct { + *StoreTestAccessory + table string `gorm:"-"` +} + +func NewTestAccessory(description string) (*TestAccessory, error) { + if description == "" { + return nil, errors.New("missing description") + } + return &TestAccessory{StoreTestAccessory: &StoreTestAccessory{Description: description}}, nil +} + +func (t *TestAccessory) Clone() interface{} { + s := proto.Clone(t.StoreTestAccessory) + return &TestAccessory{ + StoreTestAccessory: s.(*StoreTestAccessory), + } +} + +func (t *TestAccessory) TableName() string { + if t.table != "" { + return t.table + } + return defaultAccessoryTableName +} + +func (t *TestAccessory) SetTableName(name string) { + t.table = name +} + +type TestScooterAccessory struct { + *StoreTestScooterAccessory + table string `gorm:"-"` +} + +func NewTestScooterAccessory(scooterId, accessoryId uint32) (*TestScooterAccessory, error) { + if accessoryId == 0 { + return nil, errors.New("mssing accessory id") + } + return &TestScooterAccessory{ + StoreTestScooterAccessory: &StoreTestScooterAccessory{ + ScooterId: scooterId, + AccessoryId: accessoryId, + }, + }, nil +} + +func (t *TestScooterAccessory) Clone() interface{} { + s := proto.Clone(t.StoreTestScooterAccessory) + return &TestScooterAccessory{ + StoreTestScooterAccessory: s.(*StoreTestScooterAccessory), + } +} + +func (t *TestScooterAccessory) TableName() string { + if t.table != "" { + return t.table + } + return defaultScooterAccessoryTableName +} + +func (t *TestScooterAccessory) SetTableName(name string) { + t.table = name +} + type Cloner interface { Clone() interface{} } diff --git a/internal/db/db_test/db_test.pb.go b/internal/db/db_test/db_test.pb.go index b097025ad..5a0d95897 100644 --- a/internal/db/db_test/db_test.pb.go +++ b/internal/db/db_test/db_test.pb.go @@ -453,6 +453,133 @@ func (x *StoreTestScooter) GetMpg() int32 { return 0 } +// StoreTestAccessory used in the db tests only and provides a gorm resource with +// an id that's not a private or public id +type StoreTestAccessory struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: gorm:"primary_key" + AccessoryId uint32 `protobuf:"varint,1,opt,name=accessory_id,json=accessoryId,proto3" json:"accessory_id,omitempty" gorm:"primary_key"` + // @inject_tag: `gorm:"default:not_null"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" gorm:"default:not_null"` +} + +func (x *StoreTestAccessory) Reset() { + *x = StoreTestAccessory{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_storage_db_db_test_v1_db_test_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StoreTestAccessory) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StoreTestAccessory) ProtoMessage() {} + +func (x *StoreTestAccessory) ProtoReflect() protoreflect.Message { + mi := &file_controller_storage_db_db_test_v1_db_test_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 StoreTestAccessory.ProtoReflect.Descriptor instead. +func (*StoreTestAccessory) Descriptor() ([]byte, []int) { + return file_controller_storage_db_db_test_v1_db_test_proto_rawDescGZIP(), []int{4} +} + +func (x *StoreTestAccessory) GetAccessoryId() uint32 { + if x != nil { + return x.AccessoryId + } + return 0 +} + +func (x *StoreTestAccessory) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +// StoreTestScooterAccessory used in the db tests only and provides a gorm +// resource with multiple pks +type StoreTestScooterAccessory struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: gorm:"primary_key" + AccessoryId uint32 `protobuf:"varint,1,opt,name=accessory_id,json=accessoryId,proto3" json:"accessory_id,omitempty" gorm:"primary_key"` + // @inject_tag: gorm:"primary_key" + ScooterId uint32 `protobuf:"varint,2,opt,name=scooter_id,json=scooterId,proto3" json:"scooter_id,omitempty" gorm:"primary_key"` + // @inject_tag: `gorm:"default:null"` + Review string `protobuf:"bytes,3,opt,name=review,proto3" json:"review,omitempty" gorm:"default:null"` +} + +func (x *StoreTestScooterAccessory) Reset() { + *x = StoreTestScooterAccessory{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_storage_db_db_test_v1_db_test_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StoreTestScooterAccessory) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StoreTestScooterAccessory) ProtoMessage() {} + +func (x *StoreTestScooterAccessory) ProtoReflect() protoreflect.Message { + mi := &file_controller_storage_db_db_test_v1_db_test_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 StoreTestScooterAccessory.ProtoReflect.Descriptor instead. +func (*StoreTestScooterAccessory) Descriptor() ([]byte, []int) { + return file_controller_storage_db_db_test_v1_db_test_proto_rawDescGZIP(), []int{5} +} + +func (x *StoreTestScooterAccessory) GetAccessoryId() uint32 { + if x != nil { + return x.AccessoryId + } + return 0 +} + +func (x *StoreTestScooterAccessory) GetScooterId() uint32 { + if x != nil { + return x.ScooterId + } + return 0 +} + +func (x *StoreTestScooterAccessory) GetReview() string { + if x != nil { + return x.Review + } + return "" +} + var File_controller_storage_db_db_test_v1_db_test_proto protoreflect.FileDescriptor var file_controller_storage_db_db_test_v1_db_test_proto_rawDesc = []byte{ @@ -535,12 +662,25 @@ var file_controller_storage_db_db_test_v1_db_test_proto_rawDesc = []byte{ 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x70, - 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6d, 0x70, 0x67, 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, 0x64, 0x62, 0x2f, 0x64, 0x62, 0x5f, 0x74, 0x65, 0x73, - 0x74, 0x3b, 0x64, 0x62, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6d, 0x70, 0x67, 0x22, 0x59, 0x0a, 0x12, + 0x53, 0x74, 0x6f, 0x72, 0x65, 0x54, 0x65, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, + 0x72, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x79, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x6f, 0x72, 0x79, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x75, 0x0a, 0x19, 0x53, 0x74, 0x6f, 0x72, 0x65, + 0x54, 0x65, 0x73, 0x74, 0x53, 0x63, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x6f, 0x72, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, + 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x6f, 0x6f, 0x74, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x73, 0x63, 0x6f, + 0x6f, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 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, 0x64, 0x62, 0x2f, 0x64, 0x62, 0x5f, 0x74, + 0x65, 0x73, 0x74, 0x3b, 0x64, 0x62, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -555,23 +695,25 @@ func file_controller_storage_db_db_test_v1_db_test_proto_rawDescGZIP() []byte { return file_controller_storage_db_db_test_v1_db_test_proto_rawDescData } -var file_controller_storage_db_db_test_v1_db_test_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_controller_storage_db_db_test_v1_db_test_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_controller_storage_db_db_test_v1_db_test_proto_goTypes = []interface{}{ - (*StoreTestUser)(nil), // 0: controller.storage.db.db_test.v1.StoreTestUser - (*StoreTestCar)(nil), // 1: controller.storage.db.db_test.v1.StoreTestCar - (*StoreTestRental)(nil), // 2: controller.storage.db.db_test.v1.StoreTestRental - (*StoreTestScooter)(nil), // 3: controller.storage.db.db_test.v1.StoreTestScooter - (*timestamp.Timestamp)(nil), // 4: controller.storage.timestamp.v1.Timestamp + (*StoreTestUser)(nil), // 0: controller.storage.db.db_test.v1.StoreTestUser + (*StoreTestCar)(nil), // 1: controller.storage.db.db_test.v1.StoreTestCar + (*StoreTestRental)(nil), // 2: controller.storage.db.db_test.v1.StoreTestRental + (*StoreTestScooter)(nil), // 3: controller.storage.db.db_test.v1.StoreTestScooter + (*StoreTestAccessory)(nil), // 4: controller.storage.db.db_test.v1.StoreTestAccessory + (*StoreTestScooterAccessory)(nil), // 5: controller.storage.db.db_test.v1.StoreTestScooterAccessory + (*timestamp.Timestamp)(nil), // 6: controller.storage.timestamp.v1.Timestamp } var file_controller_storage_db_db_test_v1_db_test_proto_depIdxs = []int32{ - 4, // 0: controller.storage.db.db_test.v1.StoreTestUser.create_time:type_name -> controller.storage.timestamp.v1.Timestamp - 4, // 1: controller.storage.db.db_test.v1.StoreTestUser.update_time:type_name -> controller.storage.timestamp.v1.Timestamp - 4, // 2: controller.storage.db.db_test.v1.StoreTestCar.create_time:type_name -> controller.storage.timestamp.v1.Timestamp - 4, // 3: controller.storage.db.db_test.v1.StoreTestCar.update_time:type_name -> controller.storage.timestamp.v1.Timestamp - 4, // 4: controller.storage.db.db_test.v1.StoreTestRental.create_time:type_name -> controller.storage.timestamp.v1.Timestamp - 4, // 5: controller.storage.db.db_test.v1.StoreTestRental.update_time:type_name -> controller.storage.timestamp.v1.Timestamp - 4, // 6: controller.storage.db.db_test.v1.StoreTestScooter.create_time:type_name -> controller.storage.timestamp.v1.Timestamp - 4, // 7: controller.storage.db.db_test.v1.StoreTestScooter.update_time:type_name -> controller.storage.timestamp.v1.Timestamp + 6, // 0: controller.storage.db.db_test.v1.StoreTestUser.create_time:type_name -> controller.storage.timestamp.v1.Timestamp + 6, // 1: controller.storage.db.db_test.v1.StoreTestUser.update_time:type_name -> controller.storage.timestamp.v1.Timestamp + 6, // 2: controller.storage.db.db_test.v1.StoreTestCar.create_time:type_name -> controller.storage.timestamp.v1.Timestamp + 6, // 3: controller.storage.db.db_test.v1.StoreTestCar.update_time:type_name -> controller.storage.timestamp.v1.Timestamp + 6, // 4: controller.storage.db.db_test.v1.StoreTestRental.create_time:type_name -> controller.storage.timestamp.v1.Timestamp + 6, // 5: controller.storage.db.db_test.v1.StoreTestRental.update_time:type_name -> controller.storage.timestamp.v1.Timestamp + 6, // 6: controller.storage.db.db_test.v1.StoreTestScooter.create_time:type_name -> controller.storage.timestamp.v1.Timestamp + 6, // 7: controller.storage.db.db_test.v1.StoreTestScooter.update_time:type_name -> controller.storage.timestamp.v1.Timestamp 8, // [8:8] is the sub-list for method output_type 8, // [8:8] is the sub-list for method input_type 8, // [8:8] is the sub-list for extension type_name @@ -633,6 +775,30 @@ func file_controller_storage_db_db_test_v1_db_test_proto_init() { return nil } } + file_controller_storage_db_db_test_v1_db_test_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StoreTestAccessory); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_storage_db_db_test_v1_db_test_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StoreTestScooterAccessory); 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{ @@ -640,7 +806,7 @@ func file_controller_storage_db_db_test_v1_db_test_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_controller_storage_db_db_test_v1_db_test_proto_rawDesc, NumEnums: 0, - NumMessages: 4, + NumMessages: 6, NumExtensions: 0, NumServices: 0, }, diff --git a/internal/db/read_writer.go b/internal/db/read_writer.go index e942147ae..b4a78faec 100644 --- a/internal/db/read_writer.go +++ b/internal/db/read_writer.go @@ -43,9 +43,11 @@ const ( // Reader interface defines lookups/searching for resources type Reader interface { // LookupById will lookup a resource by its primary key id, which must be - // unique. The resourceWithIder must implement either ResourcePublicIder or - // ResourcePrivateIder interface. - LookupById(ctx context.Context, resourceWithIder interface{}, opt ...Option) error + // unique. If the resource implements either ResourcePublicIder or + // ResourcePrivateIder interface, then they are used as the resource's + // primary key for lookup. Otherwise, the resource tags are used to + // determine it's primary key(s) for lookup. + LookupById(ctx context.Context, resource interface{}, opt ...Option) error // LookupByPublicId will lookup resource by its public_id which must be unique. LookupByPublicId(ctx context.Context, resource ResourcePublicIder, opt ...Option) error @@ -1045,11 +1047,11 @@ func (rw *Db) LookupById(ctx context.Context, resourceWithIder interface{}, _ .. if reflect.ValueOf(resourceWithIder).Kind() != reflect.Ptr { return errors.New(ctx, errors.InvalidParameter, op, "interface parameter must to be a pointer") } - primaryKey, where, err := primaryKeyWhere(ctx, resourceWithIder) + where, keys, err := rw.primaryKeysWhere(ctx, resourceWithIder) if err != nil { return errors.Wrap(ctx, err, op) } - if err := rw.underlying.Where(where, primaryKey).First(resourceWithIder).Error; err != nil { + if err := rw.underlying.Where(where, keys...).First(resourceWithIder).Error; err != nil { if err == gorm.ErrRecordNotFound { return errors.E(ctx, errors.WithCode(errors.RecordNotFound), errors.WithOp(op), errors.WithoutEvent()) } @@ -1058,23 +1060,48 @@ func (rw *Db) LookupById(ctx context.Context, resourceWithIder interface{}, _ .. return nil } -func primaryKeyWhere(ctx context.Context, resourceWithIder interface{}) (pkey string, w string, e error) { - const op = "db.primaryKeyWhere" - var primaryKey, where string - switch resourceType := resourceWithIder.(type) { +func (rw *Db) primaryKeysWhere(ctx context.Context, i interface{}) (string, []interface{}, error) { + const op = "db.primaryKeysWhere" + var fieldNames []string + var fieldValues []interface{} + tx := rw.underlying.Model(i) + if err := tx.Statement.Parse(i); err != nil { + return "", nil, errors.Wrap(ctx, err, op, errors.WithoutEvent()) + } + switch resourceType := i.(type) { case ResourcePublicIder: - primaryKey = resourceType.GetPublicId() - where = "public_id = ?" + if resourceType.GetPublicId() == "" { + return "", nil, errors.New(ctx, errors.InvalidParameter, op, "missing primary key", errors.WithoutEvent()) + } + fieldValues = []interface{}{resourceType.GetPublicId()} + fieldNames = []string{"public_id"} case ResourcePrivateIder: - primaryKey = resourceType.GetPrivateId() - where = "private_id = ?" + if resourceType.GetPrivateId() == "" { + return "", nil, errors.New(ctx, errors.InvalidParameter, op, "missing primary key", errors.WithoutEvent()) + } + fieldValues = []interface{}{resourceType.GetPrivateId()} + fieldNames = []string{"private_id"} default: - return "", "", errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("unsupported interface type %T", resourceWithIder), errors.WithoutEvent()) + v := reflect.ValueOf(i) + for _, f := range tx.Statement.Schema.PrimaryFields { + if f.PrimaryKey { + val, isZero := f.ValueOf(v) + if isZero { + return "", nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("primary field %s is zero", f.Name)) + } + fieldNames = append(fieldNames, f.DBName) + fieldValues = append(fieldValues, val) + } + } } - if primaryKey == "" { - return "", "", errors.New(ctx, errors.InvalidParameter, op, "missing primary key", errors.WithoutEvent()) + if len(fieldNames) == 0 { + return "", nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("no primary key(s) for %t", i)) } - return primaryKey, where, nil + clauses := make([]string, 0, len(fieldNames)) + for _, col := range fieldNames { + clauses = append(clauses, fmt.Sprintf("%s = ?", col)) + } + return strings.Join(clauses, " and "), fieldValues, nil } // LookupByPublicId will lookup resource by its public_id, which must be unique. diff --git a/internal/db/read_writer_test.go b/internal/db/read_writer_test.go index 793663dd4..86eac489a 100644 --- a/internal/db/read_writer_test.go +++ b/internal/db/read_writer_test.go @@ -571,6 +571,17 @@ func TestDb_Update(t *testing.T) { assert.Equal(0, rowsUpdated) assert.Contains(err.Error(), "db.Update: oplog validation failed: db.validateOplogArgs: missing metadata: parameter violation: error #100") }) + t.Run("multi-column", func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + w := Db{underlying: db} + scooter := testScooter(t, db, "", 0) + accessory := testAccessory(t, db, "test accessory") + scooterAccessory := testScooterAccessory(t, db, scooter.Id, accessory.AccessoryId) + scooterAccessory.Review = "this is great" + rowsUpdated, err := w.Update(context.Background(), scooterAccessory, []string{"Review"}, nil) + require.NoError(err) + assert.Equal(1, rowsUpdated) + }) } // testUserWithVet gives us a model that implements VetForWrite() without any @@ -826,7 +837,7 @@ func TestDb_LookupByPublicId(t *testing.T) { require.NoError(err) err = w.LookupByPublicId(context.Background(), foundUser) require.Error(err) - assert.Contains(err.Error(), "db.LookupById: db.primaryKeyWhere: missing primary key: parameter violation: error #100") + assert.Contains(err.Error(), "db.LookupById: db.primaryKeysWhere: missing primary key: parameter violation: error #100") }) t.Run("not-found", func(t *testing.T) { assert, require := assert.New(t), require.New(t) @@ -1448,6 +1459,16 @@ func TestDb_Delete(t *testing.T) { err = TestVerifyOplog(t, &w, user.PublicId, WithOperation(oplog.OpType_OP_TYPE_UNSPECIFIED), WithCreateNotBefore(10*time.Second)) require.NoError(err) }) + t.Run("multi-column", func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + w := Db{underlying: db} + scooter := testScooter(t, db, "", 0) + accessory := testAccessory(t, db, "test accessory") + scooterAccessory := testScooterAccessory(t, db, scooter.Id, accessory.AccessoryId) + rowsDeleted, err := w.Delete(context.Background(), scooterAccessory) + require.NoError(err) + assert.Equal(1, rowsDeleted) + }) } } @@ -1983,14 +2004,41 @@ func testScooter(t *testing.T, conn *DB, model string, mpg int32) *db_test.TestS return u } +func testAccessory(t *testing.T, conn *DB, description string) *db_test.TestAccessory { + t.Helper() + require := require.New(t) + a, err := db_test.NewTestAccessory(description) + require.NoError(err) + if conn != nil { + err = conn.Create(a).Error + require.NoError(err) + } + return a +} + +func testScooterAccessory(t *testing.T, conn *DB, scooterId, accessoryId uint32) *db_test.TestScooterAccessory { + t.Helper() + require := require.New(t) + a, err := db_test.NewTestScooterAccessory(scooterId, accessoryId) + require.NoError(err) + if conn != nil { + err = conn.Create(a).Error + require.NoError(err) + } + return a +} + func TestDb_LookupById(t *testing.T) { t.Parallel() db, _ := TestSetup(t, "postgres") scooter := testScooter(t, db, "", 0) user := testUser(t, db, "", "", "") + accessory := testAccessory(t, db, "test accessory") + scooterAccessory := testScooterAccessory(t, db, scooter.Id, accessory.AccessoryId) + type args struct { - resourceWithIder interface{} - opt []Option + resource interface{} + opt []Option } tests := []struct { name string @@ -2004,7 +2052,7 @@ func TestDb_LookupById(t *testing.T) { name: "simple-private-id", underlying: db, args: args{ - resourceWithIder: scooter, + resource: scooter, }, wantErr: false, want: scooter, @@ -2013,16 +2061,47 @@ func TestDb_LookupById(t *testing.T) { name: "simple-public-id", underlying: db, args: args{ - resourceWithIder: user, + resource: user, }, wantErr: false, want: user, }, + { + name: "simple-non-public-non-private-id", + underlying: db, + args: args{ + resource: accessory, + }, + wantErr: false, + want: accessory, + }, + { + name: "compond", + underlying: db, + args: args{ + resource: scooterAccessory, + }, + wantErr: false, + want: scooterAccessory, + }, + { + name: "compond-with-zero-value-pk", + underlying: db, + args: args{ + resource: func() interface{} { + cp := scooterAccessory.Clone() + cp.(*db_test.TestScooterAccessory).ScooterId = 0 + return cp + }(), + }, + wantErr: true, + wantIsErr: errors.InvalidParameter, + }, { name: "missing-public-id", underlying: db, args: args{ - resourceWithIder: &db_test.TestUser{ + resource: &db_test.TestUser{ StoreTestUser: &db_test.StoreTestUser{}, }, }, @@ -2033,7 +2112,7 @@ func TestDb_LookupById(t *testing.T) { name: "missing-private-id", underlying: db, args: args{ - resourceWithIder: &db_test.TestScooter{ + resource: &db_test.TestScooter{ StoreTestScooter: &db_test.StoreTestScooter{}, }, }, @@ -2044,7 +2123,7 @@ func TestDb_LookupById(t *testing.T) { name: "not-an-ider", underlying: db, args: args{ - resourceWithIder: &db_test.NotIder{}, + resource: &db_test.NotIder{}, }, wantErr: true, wantIsErr: errors.InvalidParameter, @@ -2053,7 +2132,7 @@ func TestDb_LookupById(t *testing.T) { name: "missing-underlying-db", underlying: nil, args: args{ - resourceWithIder: user, + resource: user, }, wantErr: true, wantIsErr: errors.InvalidParameter, @@ -2065,13 +2144,13 @@ func TestDb_LookupById(t *testing.T) { rw := &Db{ underlying: tt.underlying, } - cloner, ok := tt.args.resourceWithIder.(db_test.Cloner) + cloner, ok := tt.args.resource.(db_test.Cloner) require.True(ok) cp := cloner.Clone() err := rw.LookupById(context.Background(), cp, tt.args.opt...) if tt.wantErr { require.Error(err) - require.True(errors.Match(errors.T(tt.wantIsErr), err)) + assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "want err code: %q got: %q", tt.wantIsErr, err) return } require.NoError(err) diff --git a/internal/db/schema/migrations/oss/postgres/19/01_db.up.sql b/internal/db/schema/migrations/oss/postgres/19/01_db.up.sql new file mode 100644 index 000000000..352e80934 --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres/19/01_db.up.sql @@ -0,0 +1,56 @@ +begin; + +create table if not exists db_test_accessory ( + accessory_id bigint generated always as identity primary key, + create_time wt_timestamp, + update_time wt_timestamp, + description text not null +); + +create trigger + update_time_column +before +update on db_test_accessory + for each row execute procedure update_time_column(); + +create trigger + immutable_columns +before +update on db_test_accessory + for each row execute procedure immutable_columns('create_time'); + +create trigger + default_create_time_column +before +insert on db_test_accessory + for each row execute procedure default_create_time(); + + +create table if not exists db_test_scooter_accessory ( + accessory_id bigint references db_test_accessory(accessory_id), + scooter_id bigint references db_test_scooter(id), + create_time wt_timestamp, + update_time wt_timestamp, + review text, + primary key(accessory_id, scooter_id) +); + +create trigger + update_time_column +before +update on db_test_scooter_accessory + for each row execute procedure update_time_column(); + +create trigger + immutable_columns +before +update on db_test_scooter_accessory + for each row execute procedure immutable_columns('create_time'); + +create trigger + default_create_time_column +before +insert on db_test_scooter_accessory + for each row execute procedure default_create_time(); + +commit; \ No newline at end of file diff --git a/internal/proto/local/controller/storage/db/db_test/v1/db_test.proto b/internal/proto/local/controller/storage/db/db_test/v1/db_test.proto index 22917ef95..4519f5932 100644 --- a/internal/proto/local/controller/storage/db/db_test/v1/db_test.proto +++ b/internal/proto/local/controller/storage/db/db_test/v1/db_test.proto @@ -118,4 +118,27 @@ message StoreTestScooter { // @inject_tag: `gorm:"default:null"` int32 mpg = 7; +} + +// StoreTestAccessory used in the db tests only and provides a gorm resource with +// an id that's not a private or public id +message StoreTestAccessory { + // @inject_tag: gorm:"primary_key" + uint32 accessory_id = 1; + + // @inject_tag: `gorm:"default:not_null"` + string description = 2; +} + +// StoreTestScooterAccessory used in the db tests only and provides a gorm +// resource with multiple pks +message StoreTestScooterAccessory { + // @inject_tag: gorm:"primary_key" + uint32 accessory_id = 1; + + // @inject_tag: gorm:"primary_key" + uint32 scooter_id = 2; + + // @inject_tag: `gorm:"default:null"` + string review = 3; } \ No newline at end of file diff --git a/internal/session/immutable_fields_test.go b/internal/session/immutable_fields_test.go index ec90235a1..96c7315e4 100644 --- a/internal/session/immutable_fields_test.go +++ b/internal/session/immutable_fields_test.go @@ -6,10 +6,12 @@ import ( "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/db/timestamp" + "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/iam" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/timestamppb" + "gorm.io/gorm/logger" ) func TestSession_ImmutableFields(t *testing.T) { @@ -245,16 +247,20 @@ func TestConnectionState_ImmutableFields(t *testing.T) { _, _ = iam.TestScopes(t, iam.TestRepo(t, conn, wrapper)) session := TestDefaultSession(t, conn, wrapper, iamRepo) connection := TestConnection(t, conn, session.PublicId, "127.0.0.1", 22, "127.0.0.1", 2222) - state := TestConnectionState(t, conn, connection.PublicId, StatusClosed) + state := TestConnectionState(t, conn, connection.PublicId, StatusConnected) var new ConnectionState err := rw.LookupWhere(context.Background(), &new, "connection_id = ? and state = ?", state.ConnectionId, state.Status) require.NoError(t, err) + conn.Logger = logger.Default.LogMode(logger.Info) + tests := []struct { - name string - update *ConnectionState - fieldMask []string + name string + update *ConnectionState + fieldMask []string + wantErrMatch *errors.Template + wantErrContains string }{ { name: "session_id", @@ -272,7 +278,9 @@ func TestConnectionState_ImmutableFields(t *testing.T) { s.Status = "closed" return s }(), - fieldMask: []string{"Status"}, + fieldMask: []string{"Status"}, + wantErrMatch: errors.T(errors.NotSpecificIntegrity), + wantErrContains: "immutable column", }, { name: "start time", @@ -281,7 +289,9 @@ func TestConnectionState_ImmutableFields(t *testing.T) { s.StartTime = &ts return s }(), - fieldMask: []string{"StartTime"}, + fieldMask: []string{"StartTime"}, + wantErrMatch: errors.T(errors.InvalidFieldMask), + wantErrContains: "parameter violation", }, { name: "previous_end_time", @@ -290,7 +300,9 @@ func TestConnectionState_ImmutableFields(t *testing.T) { s.PreviousEndTime = &ts return s }(), - fieldMask: []string{"PreviousEndTime"}, + fieldMask: []string{"PreviousEndTime"}, + wantErrMatch: errors.T(errors.NotSpecificIntegrity), + wantErrContains: "immutable column", }, } for _, tt := range tests { @@ -304,7 +316,12 @@ func TestConnectionState_ImmutableFields(t *testing.T) { rowsUpdated, err := rw.Update(context.Background(), tt.update, tt.fieldMask, nil, db.WithSkipVetForWrite(true)) require.Error(err) assert.Equal(0, rowsUpdated) - + if tt.wantErrMatch != nil { + assert.Truef(errors.Match(tt.wantErrMatch, err), "wanted error %s and got: %s", tt.wantErrMatch.Code, err.Error()) + } + if tt.wantErrContains != "" { + assert.Contains(err.Error(), tt.wantErrContains) + } after := new.Clone() err = rw.LookupWhere(context.Background(), after, "connection_id = ? and start_time = ?", new.ConnectionId, new.StartTime) require.NoError(err) From 03de1c4b2114c215d2bfefe06d9bbf738f171bf1 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 3 Nov 2021 14:52:11 -0400 Subject: [PATCH 13/15] Pass namespace to the Vault client (#1660) The namespace was plumbed all the way through the API but isn't actually set on the client when it is created. Fixes #1597 --- CHANGELOG.md | 3 +++ internal/credential/vault/vault.go | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28a28534d..bd52f521c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,9 @@ Canonical reference for changes, improvements, and bugfixes for Boundary. a missing mandated cipher suite of the HTTP/2 (`h2`) specification that could result in no shared cipher suites between the Boundary API listener and those clients. ([PR](https://github.com/hashicorp/boundary/pull/1637)) +* vault: Fix credential store support when using Vault namespaces + ([Issue](https://github.com/hashicorp/boundary/issues/1597), + [PR](https://github.com/hashicorp/boundary/pull/1660)) ## 0.6.2 (2021/09/27) diff --git a/internal/credential/vault/vault.go b/internal/credential/vault/vault.go index 9f29c6f95..0e2cc1add 100644 --- a/internal/credential/vault/vault.go +++ b/internal/credential/vault/vault.go @@ -79,6 +79,10 @@ func newClient(c *clientConfig) (*client, error) { } vClient.SetToken(string(c.Token)) + if c.Namespace != "" { + vClient.SetNamespace(c.Namespace) + } + return &client{ cl: vClient, token: c.Token, From a86ee59bcd05d8df6031cb385a8a8ddb46f7afff Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 3 Nov 2021 17:07:00 -0400 Subject: [PATCH 14/15] chore: react-subnav (#1663) --- website/package-lock.json | 30 +++++++++++++++--------------- website/package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index 0b24b5899..10b3f7b89 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -31,7 +31,7 @@ "@hashicorp/react-product-features-list": "^5.0.0", "@hashicorp/react-search": "^6.1.1", "@hashicorp/react-section-header": "^5.0.4", - "@hashicorp/react-subnav": "^9.0.1", + "@hashicorp/react-subnav": "^9.1.4", "@hashicorp/react-use-cases": "^5.0.0", "@hashicorp/react-vertical-text-block-list": "^7.0.0", "change-case": "4.1.2", @@ -1143,9 +1143,9 @@ } }, "node_modules/@hashicorp/react-button": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@hashicorp/react-button/-/react-button-6.0.1.tgz", - "integrity": "sha512-e5Kl0Nc0V9RWxrNUrig2BQlJuwTmJeZdCZJkOcUGbCwySgQ1otWkKjLRR2nOGM3v+EAkkBxhMiyBIRS2vPNrdg==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@hashicorp/react-button/-/react-button-6.0.3.tgz", + "integrity": "sha512-CRK93cWw5ap4tGGvMoyr/Ydvvz1Ie1RTyTdBhcpARlH7pCIAmvxHKMK+FCWXWGJNjpM9suKenXfdTJRfz7+KNw==", "dependencies": { "@hashicorp/platform-product-meta": "^0.1.0", "@hashicorp/react-inline-svg": "^6.0.1", @@ -1603,13 +1603,13 @@ } }, "node_modules/@hashicorp/react-subnav": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@hashicorp/react-subnav/-/react-subnav-9.0.1.tgz", - "integrity": "sha512-WRfCrkGD55qMnww+L2+tdXF04/NRY7F8XAuKqRpLpCk6ygHFvsxlsc4sn5TXpKPEPZCdcT22qlxvejjOyJ3E4g==", + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@hashicorp/react-subnav/-/react-subnav-9.1.4.tgz", + "integrity": "sha512-osbb+LzDwBRYp2IBHqjHpJXRIRFiDrMkRHw0k4DsAvb/3ZzUXD0EUqSXJGjjPxzC8m6/bsFXQnxcNUrFMshBZA==", "dependencies": { "@hashicorp/mktg-logos": "^1.0.2", "@hashicorp/platform-product-meta": "^0.1.0", - "@hashicorp/react-button": "^6.0.0", + "@hashicorp/react-button": "^6.0.3", "@hashicorp/react-inline-svg": "^6.0.3", "@hashicorp/react-link-wrap": "^3.0.3", "@reach/visually-hidden": "^0.16.0", @@ -21221,9 +21221,9 @@ } }, "@hashicorp/react-button": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@hashicorp/react-button/-/react-button-6.0.1.tgz", - "integrity": "sha512-e5Kl0Nc0V9RWxrNUrig2BQlJuwTmJeZdCZJkOcUGbCwySgQ1otWkKjLRR2nOGM3v+EAkkBxhMiyBIRS2vPNrdg==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@hashicorp/react-button/-/react-button-6.0.3.tgz", + "integrity": "sha512-CRK93cWw5ap4tGGvMoyr/Ydvvz1Ie1RTyTdBhcpARlH7pCIAmvxHKMK+FCWXWGJNjpM9suKenXfdTJRfz7+KNw==", "requires": { "@hashicorp/platform-product-meta": "^0.1.0", "@hashicorp/react-inline-svg": "^6.0.1", @@ -21597,13 +21597,13 @@ } }, "@hashicorp/react-subnav": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@hashicorp/react-subnav/-/react-subnav-9.0.1.tgz", - "integrity": "sha512-WRfCrkGD55qMnww+L2+tdXF04/NRY7F8XAuKqRpLpCk6ygHFvsxlsc4sn5TXpKPEPZCdcT22qlxvejjOyJ3E4g==", + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@hashicorp/react-subnav/-/react-subnav-9.1.4.tgz", + "integrity": "sha512-osbb+LzDwBRYp2IBHqjHpJXRIRFiDrMkRHw0k4DsAvb/3ZzUXD0EUqSXJGjjPxzC8m6/bsFXQnxcNUrFMshBZA==", "requires": { "@hashicorp/mktg-logos": "^1.0.2", "@hashicorp/platform-product-meta": "^0.1.0", - "@hashicorp/react-button": "^6.0.0", + "@hashicorp/react-button": "^6.0.3", "@hashicorp/react-inline-svg": "^6.0.3", "@hashicorp/react-link-wrap": "^3.0.3", "@reach/visually-hidden": "^0.16.0", diff --git a/website/package.json b/website/package.json index 4e787564e..646907dd6 100644 --- a/website/package.json +++ b/website/package.json @@ -27,7 +27,7 @@ "@hashicorp/react-product-features-list": "^5.0.0", "@hashicorp/react-search": "^6.1.1", "@hashicorp/react-section-header": "^5.0.4", - "@hashicorp/react-subnav": "^9.0.1", + "@hashicorp/react-subnav": "^9.1.4", "@hashicorp/react-use-cases": "^5.0.0", "@hashicorp/react-vertical-text-block-list": "^7.0.0", "change-case": "4.1.2", From dd2c3807cde9f8fc541986191fbeffa64238bcee Mon Sep 17 00:00:00 2001 From: Jim Date: Thu, 4 Nov 2021 08:55:30 -0400 Subject: [PATCH 15/15] refactor: Move functions from kms pkg to new libs/crypto pkg (#1650) --- internal/auth/oidc/auth_method.go | 21 +-- internal/auth/oidc/service.go | 3 +- .../credential/vault/client_certificate.go | 18 +- internal/credential/vault/vault_token.go | 15 +- internal/kms/kms.go | 41 ----- internal/kms/kms_test.go | 105 ----------- internal/libs/crypto/derived_reader.go | 50 ++++++ internal/libs/crypto/derived_reader_test.go | 111 ++++++++++++ internal/libs/crypto/error.go | 9 + internal/libs/crypto/hmac_sha256.go | 94 ++++++++++ internal/libs/crypto/hmac_sha256_test.go | 168 ++++++++++++++++++ internal/libs/crypto/options.go | 63 +++++++ internal/libs/crypto/options_test.go | 45 +++++ internal/libs/crypto/testing.go | 33 ++++ internal/session/util.go | 7 +- internal/session/util_test.go | 4 +- 16 files changed, 601 insertions(+), 186 deletions(-) create mode 100644 internal/libs/crypto/derived_reader.go create mode 100644 internal/libs/crypto/derived_reader_test.go create mode 100644 internal/libs/crypto/error.go create mode 100644 internal/libs/crypto/hmac_sha256.go create mode 100644 internal/libs/crypto/hmac_sha256_test.go create mode 100644 internal/libs/crypto/options.go create mode 100644 internal/libs/crypto/options_test.go create mode 100644 internal/libs/crypto/testing.go diff --git a/internal/auth/oidc/auth_method.go b/internal/auth/oidc/auth_method.go index 1f2417424..de519a68f 100644 --- a/internal/auth/oidc/auth_method.go +++ b/internal/auth/oidc/auth_method.go @@ -2,10 +2,6 @@ package oidc import ( "context" - "crypto/ed25519" - "crypto/hmac" - "crypto/sha256" - "encoding/base64" "fmt" "net/url" "sort" @@ -13,7 +9,7 @@ import ( "github.com/hashicorp/boundary/internal/auth/oidc/store" "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms" + "github.com/hashicorp/boundary/internal/libs/crypto" "github.com/hashicorp/boundary/internal/oplog" wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/go-kms-wrapping/structwrapping" @@ -236,17 +232,14 @@ func (a *AuthMethod) hmacClientSecret(ctx context.Context, cipher wrapping.Wrapp if cipher == nil { return errors.New(ctx, errors.InvalidParameter, op, "missing cipher") } - reader, err := kms.NewDerivedReader(cipher, 32, []byte(a.PublicId), nil) + // this operation currently uses the legacy WithEd25519 option for hmac'ing. + // we should likely deprecate this and introduce a new "crypto version" of + // this attribute. + hm, err := crypto.HmacSha256(ctx, []byte(a.ClientSecret), cipher, []byte(a.PublicId), nil, crypto.WithBase64Encoding(), crypto.WithEd25519()) if err != nil { - return errors.Wrap(ctx, err, op) + return errors.Wrap(ctx, err, op, errors.WithCode(errors.Code(errors.Encryption))) } - key, _, err := ed25519.GenerateKey(reader) - if err != nil { - return errors.New(ctx, errors.Encrypt, op, "unable to generate derived key") - } - mac := hmac.New(sha256.New, key) - _, _ = mac.Write([]byte(a.ClientSecret)) - a.ClientSecretHmac = base64.RawURLEncoding.EncodeToString(mac.Sum(nil)) + a.ClientSecretHmac = hm return nil } diff --git a/internal/auth/oidc/service.go b/internal/auth/oidc/service.go index 568668a62..e3a074258 100644 --- a/internal/auth/oidc/service.go +++ b/internal/auth/oidc/service.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/kms" + "github.com/hashicorp/boundary/internal/libs/crypto" wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/go-kms-wrapping/wrappers/aead" @@ -189,7 +190,7 @@ func requestWrappingWrapper(ctx context.Context, k *kms.Kms, scopeId, authMethod } // okay, I guess we need to derive a new key for this combo of oidcWrapper and authMethod - reader, err := kms.NewDerivedReader(oidcWrapper, 32, []byte(authMethodId), []byte(scopeId)) + reader, err := crypto.NewDerivedReader(oidcWrapper, 32, []byte(authMethodId), []byte(scopeId)) if err != nil { return nil, errors.Wrap(ctx, err, op) } diff --git a/internal/credential/vault/client_certificate.go b/internal/credential/vault/client_certificate.go index b368c7d72..345f97c80 100644 --- a/internal/credential/vault/client_certificate.go +++ b/internal/credential/vault/client_certificate.go @@ -2,15 +2,12 @@ package vault import ( "context" - "crypto/ed25519" - "crypto/hmac" - "crypto/sha256" "database/sql" "github.com/hashicorp/boundary/internal/credential/vault/store" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms" + "github.com/hashicorp/boundary/internal/libs/crypto" "github.com/hashicorp/boundary/internal/oplog" wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/go-kms-wrapping/structwrapping" @@ -103,17 +100,14 @@ func (c *ClientCertificate) hmacCertificateKey(ctx context.Context, cipher wrapp if cipher == nil { return errors.New(ctx, errors.InvalidParameter, op, "missing cipher") } - reader, err := kms.NewDerivedReader(cipher, 32, []byte(c.StoreId), nil) + // this operation currently uses the legacy WithEd25519 option for hmac'ing. + // we should likely deprecate this and introduce a new "crypto version" of + // this attribute. + hm, err := crypto.HmacSha256(ctx, c.CertificateKey, cipher, []byte(c.StoreId), nil, crypto.WithEd25519()) if err != nil { return errors.Wrap(ctx, err, op) } - key, _, err := ed25519.GenerateKey(reader) - if err != nil { - return errors.New(ctx, errors.Encrypt, op, "unable to generate derived key") - } - mac := hmac.New(sha256.New, key) - _, _ = mac.Write(c.CertificateKey) - c.CertificateKeyHmac = mac.Sum(nil) + c.CertificateKeyHmac = []byte(hm) return nil } diff --git a/internal/credential/vault/vault_token.go b/internal/credential/vault/vault_token.go index 5e7321f65..c653ec751 100644 --- a/internal/credential/vault/vault_token.go +++ b/internal/credential/vault/vault_token.go @@ -2,18 +2,16 @@ package vault import ( "context" - "crypto/hmac" - "crypto/sha256" "database/sql" "time" "github.com/hashicorp/boundary/internal/credential/vault/store" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" + "github.com/hashicorp/boundary/internal/libs/crypto" "github.com/hashicorp/boundary/internal/oplog" wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/go-kms-wrapping/structwrapping" - "golang.org/x/crypto/blake2b" "google.golang.org/protobuf/proto" ) @@ -74,16 +72,15 @@ func newToken(storeId string, token TokenSecret, accessor []byte, expiration tim accessorCopy := make([]byte, len(accessor)) copy(accessorCopy, accessor) - key := blake2b.Sum256(accessorCopy) - mac := hmac.New(sha256.New, key[:]) - _, _ = mac.Write(tokenCopy) - hmac := mac.Sum(nil) - + hmac, err := crypto.HmacSha256WithPrk(context.Background(), tokenCopy, accessorCopy) + if err != nil { + return nil, errors.WrapDeprecated(err, op, errors.WithCode(errors.Encrypt)) + } t := &Token{ expiration: expiration.Round(time.Second), Token: &store.Token{ StoreId: storeId, - TokenHmac: hmac, + TokenHmac: []byte(hmac), Token: tokenCopy, Status: string(CurrentToken), }, diff --git a/internal/kms/kms.go b/internal/kms/kms.go index 11b2ddcdd..9e0f64e36 100644 --- a/internal/kms/kms.go +++ b/internal/kms/kms.go @@ -2,9 +2,7 @@ package kms import ( "context" - "crypto/sha256" "fmt" - "io" "sync" "github.com/hashicorp/boundary/internal/db" @@ -13,7 +11,6 @@ import ( wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/go-kms-wrapping/wrappers/aead" "github.com/hashicorp/go-kms-wrapping/wrappers/multiwrapper" - "golang.org/x/crypto/hkdf" ) // ExternalWrappers holds wrappers defined outside of Boundary, e.g. in its @@ -371,41 +368,3 @@ func (k *Kms) loadDek(ctx context.Context, scopeId string, purpose KeyPurpose, r return multi, nil } - -// DerivedReader returns a reader from which keys can be read, using the -// given wrapper, reader length limit, salt and context info. Salt and info can -// be nil. -// -// Example: -// reader, _ := NewDerivedReader(wrapper, userId, jobId) -// key := ed25519.GenerateKey(reader) -func NewDerivedReader(wrapper wrapping.Wrapper, lenLimit int64, salt, info []byte) (*io.LimitedReader, error) { - const op = "kms.NewDerivedReader" - if wrapper == nil { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing wrapper") - } - if lenLimit < 20 { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "lenLimit must be >= 20") - } - var aeadWrapper *aead.Wrapper - switch w := wrapper.(type) { - case *multiwrapper.MultiWrapper: - raw := w.WrapperForKeyID("__base__") - var ok bool - if aeadWrapper, ok = raw.(*aead.Wrapper); !ok { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "unexpected wrapper type from multiwrapper base") - } - case *aead.Wrapper: - if w.GetKeyBytes() == nil { - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "aead wrapper missing bytes") - } - aeadWrapper = w - default: - return nil, errors.NewDeprecated(errors.InvalidParameter, op, "unknown wrapper type") - } - reader := hkdf.New(sha256.New, aeadWrapper.GetKeyBytes(), salt, info) - return &io.LimitedReader{ - R: reader, - N: lenLimit, - }, nil -} diff --git a/internal/kms/kms_test.go b/internal/kms/kms_test.go index dbd8e964e..0ce3bb44b 100644 --- a/internal/kms/kms_test.go +++ b/internal/kms/kms_test.go @@ -3,19 +3,12 @@ package kms import ( "context" "crypto/rand" - "crypto/sha256" - "io" "testing" "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/types/scope" - wrapping "github.com/hashicorp/go-kms-wrapping" - "github.com/hashicorp/go-kms-wrapping/wrappers/aead" "github.com/hashicorp/go-uuid" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "golang.org/x/crypto/hkdf" ) func TestKms_KeyId(t *testing.T) { @@ -73,101 +66,3 @@ func TestKms_KeyId(t *testing.T) { _, err = kmsCache.GetWrapper(ctx, scope.Global.String(), KeyPurposeDatabase, WithKeyId("foo")) require.Error(err) } - -func TestNewDerivedReader(t *testing.T) { - wrapper := db.TestWrapper(t) - - type args struct { - wrapper wrapping.Wrapper - lenLimit int64 - salt []byte - info []byte - } - tests := []struct { - name string - args args - want *io.LimitedReader - wantErr bool - wantErrCode errors.Code - wantErrContains string - }{ - { - name: "valid-with-salt", - args: args{ - wrapper: wrapper, - lenLimit: 32, - info: nil, - salt: []byte("salt"), - }, - want: &io.LimitedReader{ - R: hkdf.New(sha256.New, wrapper.(*aead.Wrapper).GetKeyBytes(), []byte("salt"), nil), - N: 32, - }, - }, - { - name: "valid-with-salt-info", - args: args{ - wrapper: wrapper, - lenLimit: 32, - info: []byte("info"), - salt: []byte("salt"), - }, - want: &io.LimitedReader{ - R: hkdf.New(sha256.New, wrapper.(*aead.Wrapper).GetKeyBytes(), []byte("salt"), []byte("info")), - N: 32, - }, - }, - { - name: "nil-wrapper", - args: args{ - wrapper: nil, - lenLimit: 10, - info: []byte("info"), - salt: []byte("salt"), - }, - wantErr: true, - wantErrCode: errors.InvalidParameter, - wantErrContains: "missing wrapper", - }, - { - name: "too-short", - args: args{ - wrapper: wrapper, - lenLimit: 10, - info: []byte("info"), - salt: []byte("salt"), - }, - wantErr: true, - wantErrCode: errors.InvalidParameter, - wantErrContains: "lenLimit must be >= 20", - }, - { - name: "wrapper-with-no-bytes", - args: args{ - wrapper: &aead.Wrapper{}, - lenLimit: 32, - info: nil, - salt: []byte("salt"), - }, - wantErr: true, - wantErrCode: errors.InvalidParameter, - wantErrContains: "missing bytes", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - got, err := NewDerivedReader(tt.args.wrapper, tt.args.lenLimit, tt.args.salt, tt.args.info) - if tt.wantErr { - require.Error(err) - assert.Truef(errors.Match(errors.T(errors.InvalidParameter), err), "unexpected error: %s", err) - if tt.wantErrContains != "" { - assert.Contains(err.Error(), tt.wantErrContains) - } - return - } - require.NoError(err) - assert.Equal(tt.want, got) - }) - } -} diff --git a/internal/libs/crypto/derived_reader.go b/internal/libs/crypto/derived_reader.go new file mode 100644 index 000000000..387d65d4d --- /dev/null +++ b/internal/libs/crypto/derived_reader.go @@ -0,0 +1,50 @@ +package crypto + +import ( + "crypto/sha256" + "fmt" + "io" + + wrapping "github.com/hashicorp/go-kms-wrapping" + "github.com/hashicorp/go-kms-wrapping/wrappers/aead" + "github.com/hashicorp/go-kms-wrapping/wrappers/multiwrapper" + "golang.org/x/crypto/hkdf" +) + +// DerivedReader returns a reader from which keys can be read, using the +// given wrapper, reader length limit, salt and context info. Salt and info can +// be nil. +// +// Example: +// reader, _ := NewDerivedReader(wrapper, userId, jobId) +// key := ed25519.GenerateKey(reader) +func NewDerivedReader(wrapper wrapping.Wrapper, lenLimit int64, salt, info []byte) (*io.LimitedReader, error) { + const op = "crypto.NewDerivedReader" + if wrapper == nil { + return nil, fmt.Errorf("%s: missing wrapper: %w", op, ErrInvalidParameter) + } + if lenLimit < 20 { + return nil, fmt.Errorf("%s: lenLimit must be >= 20: %w", op, ErrInvalidParameter) + } + var aeadWrapper *aead.Wrapper + switch w := wrapper.(type) { + case *multiwrapper.MultiWrapper: + raw := w.WrapperForKeyID("__base__") + var ok bool + if aeadWrapper, ok = raw.(*aead.Wrapper); !ok { + return nil, fmt.Errorf("%s: unexpected wrapper type from multiwrapper base: %w", op, ErrInvalidParameter) + } + case *aead.Wrapper: + if w.GetKeyBytes() == nil { + return nil, fmt.Errorf("%s: aead wrapper missing bytes: %w", op, ErrInvalidParameter) + } + aeadWrapper = w + default: + return nil, fmt.Errorf("%s: unknown wrapper type: %w", op, ErrInvalidParameter) + } + reader := hkdf.New(sha256.New, aeadWrapper.GetKeyBytes(), salt, info) + return &io.LimitedReader{ + R: reader, + N: lenLimit, + }, nil +} diff --git a/internal/libs/crypto/derived_reader_test.go b/internal/libs/crypto/derived_reader_test.go new file mode 100644 index 000000000..bcd6d86a9 --- /dev/null +++ b/internal/libs/crypto/derived_reader_test.go @@ -0,0 +1,111 @@ +package crypto + +import ( + "crypto/sha256" + "io" + "testing" + + wrapping "github.com/hashicorp/go-kms-wrapping" + "github.com/hashicorp/go-kms-wrapping/wrappers/aead" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/crypto/hkdf" +) + +func TestNewDerivedReader(t *testing.T) { + wrapper := TestWrapper(t) + + type args struct { + wrapper wrapping.Wrapper + lenLimit int64 + salt []byte + info []byte + } + tests := []struct { + name string + args args + want *io.LimitedReader + wantErr bool + wantErrCode error + wantErrContains string + }{ + { + name: "valid-with-salt", + args: args{ + wrapper: wrapper, + lenLimit: 32, + info: nil, + salt: []byte("salt"), + }, + want: &io.LimitedReader{ + R: hkdf.New(sha256.New, wrapper.(*aead.Wrapper).GetKeyBytes(), []byte("salt"), nil), + N: 32, + }, + }, + { + name: "valid-with-salt-info", + args: args{ + wrapper: wrapper, + lenLimit: 32, + info: []byte("info"), + salt: []byte("salt"), + }, + want: &io.LimitedReader{ + R: hkdf.New(sha256.New, wrapper.(*aead.Wrapper).GetKeyBytes(), []byte("salt"), []byte("info")), + N: 32, + }, + }, + { + name: "nil-wrapper", + args: args{ + wrapper: nil, + lenLimit: 10, + info: []byte("info"), + salt: []byte("salt"), + }, + wantErr: true, + wantErrCode: ErrInvalidParameter, + wantErrContains: "missing wrapper", + }, + { + name: "too-short", + args: args{ + wrapper: wrapper, + lenLimit: 10, + info: []byte("info"), + salt: []byte("salt"), + }, + wantErr: true, + wantErrCode: ErrInvalidParameter, + wantErrContains: "lenLimit must be >= 20", + }, + { + name: "wrapper-with-no-bytes", + args: args{ + wrapper: &aead.Wrapper{}, + lenLimit: 32, + info: nil, + salt: []byte("salt"), + }, + wantErr: true, + wantErrCode: ErrInvalidParameter, + wantErrContains: "missing bytes", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + got, err := NewDerivedReader(tt.args.wrapper, tt.args.lenLimit, tt.args.salt, tt.args.info) + if tt.wantErr { + require.Error(err) + assert.ErrorIsf(err, tt.wantErrCode, "unexpected error: %s", err) + if tt.wantErrContains != "" { + assert.Contains(err.Error(), tt.wantErrContains) + } + return + } + require.NoError(err) + assert.Equal(tt.want, got) + }) + } +} diff --git a/internal/libs/crypto/error.go b/internal/libs/crypto/error.go new file mode 100644 index 000000000..6e97908cc --- /dev/null +++ b/internal/libs/crypto/error.go @@ -0,0 +1,9 @@ +package crypto + +import ( + "errors" +) + +var ( + ErrInvalidParameter = errors.New("Invalid parameter") +) diff --git a/internal/libs/crypto/hmac_sha256.go b/internal/libs/crypto/hmac_sha256.go new file mode 100644 index 000000000..05491e6ef --- /dev/null +++ b/internal/libs/crypto/hmac_sha256.go @@ -0,0 +1,94 @@ +package crypto + +import ( + "context" + "crypto/ed25519" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "fmt" + "io" + + wrapping "github.com/hashicorp/go-kms-wrapping" + "golang.org/x/crypto/blake2b" +) + +// HmacSha256WithPrk will HmacSha256 using the provided prk. See HmacSha256 for +// options supported. +func HmacSha256WithPrk(ctx context.Context, data, prk []byte, opt ...Option) (string, error) { + opt = append(opt, WithPrk(prk)) + return HmacSha256(ctx, data, nil, nil, nil, opt...) +} + +// HmacSha256 the provided data. Supports WithPrefix, WithEd25519 and WithPrk +// options. WithEd25519 is a "legacy" way to complete this operation and should +// not be used in new operations unless backward compatibility is needed. The +// WithPrefix option will prepend the prefix to the hmac-sha256 value. +func HmacSha256(ctx context.Context, data []byte, cipher wrapping.Wrapper, salt, info []byte, opt ...Option) (string, error) { + const op = "crypto.HmacSha256" + opts, err := getOpts(opt...) + if err != nil { + return "", fmt.Errorf("%s: unable to get options: %w", op, err) + } + if data == nil { + return "", fmt.Errorf("%s: missing data: %w", op, ErrInvalidParameter) + } + if cipher == nil && opts.withPrk == nil { + return "", fmt.Errorf("%s: you must specify either a wrapper or prk: %w", op, ErrInvalidParameter) + } + if cipher != nil && opts.withPrk != nil { + return "", fmt.Errorf("%s: you cannot specify both a wrapper or prk: %w", op, ErrInvalidParameter) + } + if opts.withEd25519 && opts.withPrk != nil { + return "", fmt.Errorf("%s: you cannot specify both ed25519 and a prk: %w", op, ErrInvalidParameter) + } + var key [32]byte + switch { + case opts.withPrk != nil: + key = blake2b.Sum256(opts.withPrk) + + case opts.withEd25519: + reader, err := NewDerivedReader(cipher, 32, salt, info) + if err != nil { + return "", fmt.Errorf("%s: %w", op, err) + } + edKey, _, err := ed25519.GenerateKey(reader) + if err != nil { + return "", fmt.Errorf("%s: unable to generate derived key: %w", op, ErrInvalidParameter) + } + n := copy(key[:], edKey) + if n != 32 { + return "", fmt.Errorf("%s: expected to copy 32 bytes and got: %d", op, n) + } + + default: + reader, err := NewDerivedReader(cipher, 32, salt, info) + if err != nil { + return "", fmt.Errorf("%s: %w", op, err) + } + readerKey := make([]byte, 32) + n, err := io.ReadFull(reader, readerKey) + if err != nil { + return "", fmt.Errorf("%s: %w", op, err) + } + if n != 32 { + return "", fmt.Errorf("%s: expected to read 32 bytes and got: %d", op, n) + } + key = blake2b.Sum256(readerKey) + } + mac := hmac.New(sha256.New, key[:]) + _, _ = mac.Write(data) + hmac := mac.Sum(nil) + + var hmacString string + switch opts.withBase64Encoding { + case true: + hmacString = base64.RawURLEncoding.EncodeToString(hmac) + case false: + hmacString = string(hmac) + } + if opts.withPrefix != "" { + return opts.withPrefix + hmacString, nil + } + return hmacString, nil +} diff --git a/internal/libs/crypto/hmac_sha256_test.go b/internal/libs/crypto/hmac_sha256_test.go new file mode 100644 index 000000000..41782c830 --- /dev/null +++ b/internal/libs/crypto/hmac_sha256_test.go @@ -0,0 +1,168 @@ +package crypto + +import ( + "context" + "crypto/ed25519" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "io" + "testing" + + wrapping "github.com/hashicorp/go-kms-wrapping" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/crypto/blake2b" +) + +func Test_HmacSha256(t *testing.T) { + testCtx := context.Background() + testWrapper := TestWrapper(t) + tests := []struct { + name string + data []byte + wrapper wrapping.Wrapper + salt []byte + info []byte + opts []Option + wantHmac string + wantErr bool + wantErrIs error + }{ + { + name: "missing data", + wrapper: testWrapper, + wantErr: true, + wantErrIs: ErrInvalidParameter, + }, + { + name: "missing wrapper", + data: []byte("test"), + wantErr: true, + wantErrIs: ErrInvalidParameter, + }, + { + name: "prk-and-ed25519", + data: []byte("test"), + wrapper: testWrapper, + opts: []Option{WithPrk([]byte("prk")), WithEd25519()}, + wantErr: true, + wantErrIs: ErrInvalidParameter, + }, + { + name: "prk-and-wrapper", + data: []byte("test"), + wrapper: testWrapper, + opts: []Option{WithPrk([]byte("prk")), WithEd25519()}, + wantErr: true, + wantErrIs: ErrInvalidParameter, + }, + { + name: "blake2b-with-prefix", + data: []byte("test"), + wrapper: testWrapper, + opts: []Option{WithPrefix("prefix:")}, + wantHmac: testWithBlake2b(t, []byte("test"), testWrapper, nil, nil, WithPrefix("prefix:")), + }, + { + name: "blake2b-with-prefix-with-bas64", + data: []byte("test"), + wrapper: testWrapper, + opts: []Option{WithPrefix("prefix:"), WithBase64Encoding()}, + wantHmac: testWithBlake2b(t, []byte("test"), testWrapper, nil, nil, WithPrefix("prefix:"), WithBase64Encoding()), + }, + { + name: "with-prk", + data: []byte("test"), + opts: []Option{WithPrk([]byte("prk-0123456789012345678901234567890"))}, + wantHmac: testWithBlake2b(t, []byte("test"), testWrapper, nil, nil, WithPrk([]byte("prk-0123456789012345678901234567890"))), + }, + { + name: "withEd25519", + data: []byte("test"), + wrapper: testWrapper, + opts: []Option{WithEd25519()}, + wantHmac: testWithEd25519(t, []byte("test"), testWrapper, nil, nil), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + hm, err := HmacSha256(testCtx, tt.data, tt.wrapper, tt.salt, tt.info, tt.opts...) + if tt.wantErr { + require.Error(err) + if tt.wantErrIs != nil { + assert.ErrorIs(err, tt.wantErrIs) + } + return + } + require.NoError(err) + assert.Equal(tt.wantHmac, hm) + }) + } + + t.Run("HmacSha256WithPrk", func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + hm, err := HmacSha256WithPrk(testCtx, []byte("test"), []byte("prk-0123456789012345678901234567890")) + require.NoError(err) + want := testWithBlake2b(t, []byte("test"), testWrapper, nil, nil, WithPrk([]byte("prk-0123456789012345678901234567890"))) + assert.Equal(want, hm) + }) +} + +func testWithEd25519(t *testing.T, data []byte, w wrapping.Wrapper, salt, info []byte, opt ...Option) string { + t.Helper() + require := require.New(t) + reader, err := NewDerivedReader(w, 32, salt, info) + require.NoError(err) + edKey, _, err := ed25519.GenerateKey(reader) + require.NoError(err) + var key [32]byte + n := copy(key[:], edKey) + require.Equal(n, 32) + return testHmac(t, key[:], data, opt...) +} + +func testWithBlake2b(t *testing.T, data []byte, w wrapping.Wrapper, salt, info []byte, opt ...Option) string { + t.Helper() + require := require.New(t) + require.NotNil(data) + require.NotNil(w) + opts, err := getOpts(opt...) + require.NoError(err) + var key [32]byte + switch { + case opts.withPrk != nil: + key = blake2b.Sum256(opts.withPrk) + default: + reader, err := NewDerivedReader(w, 32, salt, info) + require.NoError(err) + readerKey := make([]byte, 32) + n, err := io.ReadFull(reader, readerKey) + require.NoError(err) + require.Equal(n, 32) + key = blake2b.Sum256(readerKey) + } + return testHmac(t, key[:], data, opt...) +} + +func testHmac(t *testing.T, key, data []byte, opt ...Option) string { + t.Helper() + require := require.New(t) + mac := hmac.New(sha256.New, key) + _, _ = mac.Write(data) + hmac := mac.Sum(nil) + var hmacString string + opts, err := getOpts(opt...) + require.NoError(err) + switch opts.withBase64Encoding { + case true: + hmacString = base64.RawURLEncoding.EncodeToString(hmac) + case false: + hmacString = string(hmac) + } + if opts.withPrefix != "" { + return opts.withPrefix + hmacString + } + return hmacString +} diff --git a/internal/libs/crypto/options.go b/internal/libs/crypto/options.go new file mode 100644 index 000000000..e3a88e312 --- /dev/null +++ b/internal/libs/crypto/options.go @@ -0,0 +1,63 @@ +package crypto + +// getOpts - iterate the inbound Options and return a struct. +func getOpts(opt ...Option) (*options, error) { + opts := getDefaultOptions() + for _, o := range opt { + if o != nil { + if err := o(opts); err != nil { + return nil, err + } + } + } + return opts, nil +} + +// Option - how Options are passed as arguments. +type Option func(*options) error + +// options = how options are represented +type options struct { + withPrefix string + withPrk []byte + withEd25519 bool + withBase64Encoding bool +} + +func getDefaultOptions() *options { + return &options{} +} + +// WithPrefix allows an optional prefix to be specified for the data returned +func WithPrefix(prefix string) Option { + return func(o *options) error { + o.withPrefix = prefix + return nil + } +} + +// WithPrk allows an optional PRK (pseudorandom key) to be specified for an +// operation. If you're using this option with HmacSha256, you might consider +// using HmacSha256WithPrk instead. +func WithPrk(prk []byte) Option { + return func(o *options) error { + o.withPrk = prk + return nil + } +} + +// WithEd25519 allows an optional request to use ed25519 during the operation +func WithEd25519() Option { + return func(o *options) error { + o.withEd25519 = true + return nil + } +} + +// WithBase64Encoding allows an optional request to base64 encode the data returned +func WithBase64Encoding() Option { + return func(o *options) error { + o.withBase64Encoding = true + return nil + } +} diff --git a/internal/libs/crypto/options_test.go b/internal/libs/crypto/options_test.go new file mode 100644 index 000000000..f44b87eda --- /dev/null +++ b/internal/libs/crypto/options_test.go @@ -0,0 +1,45 @@ +package crypto + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// Test_GetOpts provides unit tests for GetOpts and all the options +func Test_GetOpts(t *testing.T) { + t.Parallel() + t.Run("WithPrefix", func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + opts, err := getOpts(WithPrefix("test")) + require.NoError(err) + testOpts := getDefaultOptions() + testOpts.withPrefix = "test" + assert.Equal(opts, testOpts) + }) + t.Run("WithPrk", func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + opts, err := getOpts(WithPrk([]byte("test"))) + require.NoError(err) + testOpts := getDefaultOptions() + testOpts.withPrk = []byte("test") + assert.Equal(opts, testOpts) + }) + t.Run("WithEd25519", func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + opts, err := getOpts(WithEd25519()) + require.NoError(err) + testOpts := getDefaultOptions() + testOpts.withEd25519 = true + assert.Equal(opts, testOpts) + }) + t.Run("WithBase64Encoding", func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + opts, err := getOpts(WithBase64Encoding()) + require.NoError(err) + testOpts := getDefaultOptions() + testOpts.withBase64Encoding = true + assert.Equal(opts, testOpts) + }) +} diff --git a/internal/libs/crypto/testing.go b/internal/libs/crypto/testing.go new file mode 100644 index 000000000..d470cebc8 --- /dev/null +++ b/internal/libs/crypto/testing.go @@ -0,0 +1,33 @@ +package crypto + +import ( + "crypto/rand" + "encoding/base64" + "testing" + + wrapping "github.com/hashicorp/go-kms-wrapping" + "github.com/hashicorp/go-kms-wrapping/wrappers/aead" +) + +// TestWrapper initializes an AEAD wrapping.Wrapper for testing +func TestWrapper(t *testing.T) wrapping.Wrapper { + rootKey := make([]byte, 32) + n, err := rand.Read(rootKey) + if err != nil { + t.Fatal(err) + } + if n != 32 { + t.Fatal(n) + } + root := aead.NewWrapper(nil) + _, err = root.SetConfig(map[string]string{ + "key_id": base64.StdEncoding.EncodeToString(rootKey), + }) + if err != nil { + t.Fatal(err) + } + if err := root.SetAESGCMKeyBytes(rootKey); err != nil { + t.Fatal(err) + } + return root +} diff --git a/internal/session/util.go b/internal/session/util.go index bbdbe6316..f94f98dd9 100644 --- a/internal/session/util.go +++ b/internal/session/util.go @@ -4,7 +4,7 @@ import ( "crypto/ed25519" "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms" + "github.com/hashicorp/boundary/internal/libs/crypto" wrapping "github.com/hashicorp/go-kms-wrapping" ) @@ -19,8 +19,11 @@ func DeriveED25519Key(wrapper wrapping.Wrapper, userId, jobId string) (ed25519.P if jobId != "" { jId = []byte(jobId) } + if wrapper == nil { + return nil, nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing wrapper") + } - reader, err := kms.NewDerivedReader(wrapper, 32, uId, jId) + reader, err := crypto.NewDerivedReader(wrapper, 32, uId, jId) if err != nil { return nil, nil, errors.WrapDeprecated(err, op) } diff --git a/internal/session/util_test.go b/internal/session/util_test.go index 78203ec14..09e8eee1c 100644 --- a/internal/session/util_test.go +++ b/internal/session/util_test.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/kms" + "github.com/hashicorp/boundary/internal/libs/crypto" wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -39,7 +39,7 @@ func TestDeriveED25519Key(t *testing.T) { jobId: "jobId", }, want: func() keys { - reader, err := kms.NewDerivedReader(wrapper, 32, []byte("userId"), []byte("jobId")) + reader, err := crypto.NewDerivedReader(wrapper, 32, []byte("userId"), []byte("jobId")) require.NoError(t, err) pub, priv, err := ed25519.GenerateKey(reader) require.NoError(t, err)