feat(target): Add support for static credentials during authorize-session

This commit is contained in:
Louis Ruch committed 2022-06-14 13:04:35 -07:00
1 parent c14fe05036
commit 4b365db634
11 files changed
+519 -236

No files matched your search

+1 -1
View File
@@ -78,7 +78,7 @@ func fmtSecretForTable(indent int, sc *targets.SessionCredential) []string {
prefixStr := strings.Repeat(" ", indent)
origSecret := []string{fmt.Sprintf("%s %s", prefixStr, sc.Secret.Raw)}
switch sc.CredentialSource.Type {
case "vault":
case "vault", "static":
if sc.Credential != nil {
maxLength := 0
for k := range sc.Credential {
+1 -1
View File
@@ -888,7 +888,7 @@ func printCustomActionOutputImpl(c *Command) (bool, error) {
var secretStr []string
switch cred.CredentialSource.Type {
case "vault":
case "vault", "static":
switch {
case cred.Credential != nil:
maxLength := 0
+2 -1
View File
@@ -175,7 +175,8 @@ func (c *Controller) registerGrpcServices(s *grpc.Server) error {
c.SessionRepoFn,
c.PluginHostRepoFn,
c.StaticHostRepoFn,
c.VaultCredentialRepoFn)
c.VaultCredentialRepoFn,
c.StaticCredentialRepoFn)
if err != nil {
return fmt.Errorf("failed to create target handler service: %w", err)
}
@@ -0,0 +1,198 @@
package targets
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"github.com/hashicorp/boundary/internal/credential"
credstatic "github.com/hashicorp/boundary/internal/credential/static"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
"github.com/hashicorp/boundary/internal/errors"
serverpb "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/boundary/internal/types/subtypes"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
)
// dynamicToWorkerCredential converts the strongly typed credential.Dynamic into
// a session.Credential suitable for passing to a Boundary worker.
func dynamicToWorkerCredential(ctx context.Context, cred credential.Dynamic) (session.Credential, error) {
const op = "targets.dynamicToWorkerCredential"
var workerCred *serverpb.Credential
switch c := cred.(type) {
case credential.UsernamePassword:
workerCred = &serverpb.Credential{
Credential: &serverpb.Credential_UserPassword{
UserPassword: &serverpb.UserPassword{
Username: c.Username(),
Password: string(c.Password()),
},
},
}
default:
return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("unsupported credential %T", c))
}
data, err := proto.Marshal(workerCred)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("marshalling dynamic secret to proto"))
}
return data, nil
}
func dynamicToSessionCredential(ctx context.Context, cred credential.Dynamic) (*pb.SessionCredential, error) {
const op = "targets.dynamicToSessionCredential"
l := cred.Library()
secret := cred.Secret()
// TODO: Access the json directly from the vault response instead of re-marshalling it.
jSecret, err := json.Marshal(secret)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("marshalling secret to json"))
}
var sSecret *structpb.Struct
switch secret.(type) {
case map[string]interface{}:
// In this case we actually have to re-decode it. The proto wrappers
// choke on json.Number and at the time I'm writing this I don't
// have time to write a walk function to dig through with reflect
// and find all json.Numbers and replace them. So we eat the
// inefficiency. So note that we are specifically _not_ using a
// decoder with UseNumber here.
var dSecret map[string]interface{}
if err := json.Unmarshal(jSecret, &dSecret); err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("decoding json for proto marshaling"))
}
sSecret, err = structpb.NewStruct(dSecret)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("creating proto struct for secret"))
}
}
var credType string
var credData *structpb.Struct
if l.CredentialType() != credential.UnspecifiedType {
credType = string(l.CredentialType())
switch c := cred.(type) {
case credential.UsernamePassword:
credData, err = handlers.ProtoToStruct(
&pb.UserPasswordCredential{
Username: c.Username(),
Password: string(c.Password()),
},
)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("creating proto struct for credential"))
}
default:
return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("unsupported credential %T", c))
}
}
return &pb.SessionCredential{
CredentialLibrary: &pb.CredentialLibrary{
Id: l.GetPublicId(),
Name: l.GetName(),
Description: l.GetDescription(),
CredentialStoreId: l.GetStoreId(),
Type: subtypes.SubtypeFromId(credentialDomain, l.GetPublicId()).String(),
},
CredentialSource: &pb.CredentialSource{
Id: l.GetPublicId(),
Name: l.GetName(),
Description: l.GetDescription(),
CredentialStoreId: l.GetStoreId(),
Type: subtypes.SubtypeFromId(credentialDomain, l.GetPublicId()).String(),
CredentialType: credType,
},
Secret: &pb.SessionSecret{
Raw: base64.StdEncoding.EncodeToString(jSecret),
Decoded: sSecret,
},
Credential: credData,
}, nil
}
// staticToWorkerCredential converts the credential.Static into
// a session.Credential suitable for passing to a Boundary worker.
func staticToWorkerCredential(ctx context.Context, cred credential.Static) (session.Credential, error) {
const op = "targets.staticToWorkerCredential"
var workerCred *serverpb.Credential
switch c := cred.(type) {
case credstatic.UsernamePasswordCredential:
workerCred = &serverpb.Credential{
Credential: &serverpb.Credential_UserPassword{
UserPassword: &serverpb.UserPassword{
Username: c.GetUsername(),
Password: string(c.GetPassword()),
},
},
}
default:
return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("unsupported credential %T", c))
}
data, err := proto.Marshal(workerCred)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("marshalling dynamic secret to proto"))
}
return data, nil
}
func staticToSessionCredential(ctx context.Context, cred credential.Static) (*pb.SessionCredential, error) {
const op = "targets.staticToSessionCredential"
var credType string
var credData *structpb.Struct
var secret map[string]interface{}
switch c := cred.(type) {
case *credstatic.UsernamePasswordCredential:
var err error
credType = string(credential.UsernamePasswordType)
credData, err = handlers.ProtoToStruct(
&pb.UserPasswordCredential{
Username: c.GetUsername(),
Password: string(c.GetPassword()),
},
)
secret = map[string]interface{}{
"username": c.GetUsername(),
"password": string(c.GetPassword()),
}
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("creating proto struct for static credential"))
}
default:
return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("unsupported credential %T", c))
}
jSecret, err := json.Marshal(secret)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("marshalling static secret to json"))
}
sSecret, err := structpb.NewStruct(secret)
return &pb.SessionCredential{
CredentialSource: &pb.CredentialSource{
Id: cred.GetPublicId(),
Name: cred.GetName(),
Description: cred.GetDescription(),
CredentialStoreId: cred.GetStoreId(),
Type: credstatic.Subtype.String(),
CredentialType: credType,
},
Secret: &pb.SessionSecret{
Raw: base64.StdEncoding.EncodeToString(jSecret),
Decoded: sSecret,
},
Credential: credData,
}, nil
}
@@ -2,8 +2,6 @@ package targets
import (
"context"
"encoding/base64"
"encoding/json"
stderrors "errors"
"fmt"
"math/rand"
@@ -23,7 +21,6 @@ import (
"github.com/hashicorp/boundary/internal/db/timestamp"
"github.com/hashicorp/boundary/internal/errors"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
serverpb "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
"github.com/hashicorp/boundary/internal/host"
"github.com/hashicorp/boundary/internal/host/plugin"
"github.com/hashicorp/boundary/internal/host/static"
@@ -44,7 +41,6 @@ import (
"github.com/mr-tron/base58"
"google.golang.org/grpc/codes"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
"google.golang.org/protobuf/types/known/wrapperspb"
)
@@ -97,6 +93,7 @@ type Service struct {
pluginHostRepoFn common.PluginHostRepoFactory
staticHostRepoFn common.StaticRepoFactory
vaultCredRepoFn common.VaultCredentialRepoFactory
staticCredRepoFn common.StaticCredentialRepoFactory
kmsCache *kms.Kms
}
@@ -111,6 +108,7 @@ func NewService(
pluginHostRepoFn common.PluginHostRepoFactory,
staticHostRepoFn common.StaticRepoFactory,
vaultCredRepoFn common.VaultCredentialRepoFactory,
staticCredRepoFn common.StaticCredentialRepoFactory,
) (Service, error) {
const op = "targets.NewService"
if repoFn == nil {
@@ -134,6 +132,9 @@ func NewService(
if vaultCredRepoFn == nil {
return Service{}, errors.New(ctx, errors.InvalidParameter, op, "missing vault credential repository")
}
if staticCredRepoFn == nil {
return Service{}, errors.New(ctx, errors.InvalidParameter, op, "missing static credential repository")
}
return Service{
repoFn: repoFn,
iamRepoFn: iamRepoFn,
@@ -142,6 +143,7 @@ func NewService(
pluginHostRepoFn: pluginHostRepoFn,
staticHostRepoFn: staticHostRepoFn,
vaultCredRepoFn: vaultCredRepoFn,
staticCredRepoFn: staticCredRepoFn,
kmsCache: kmsCache,
}, nil
}
@@ -873,7 +875,7 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
if err != nil {
return nil, err
}
t, hostSources, libs, err := repo.LookupTarget(ctx, t.GetPublicId())
t, hostSources, credSources, err := repo.LookupTarget(ctx, t.GetPublicId())
if err != nil {
if errors.IsNotFoundError(err) {
return nil, handlers.NotFoundErrorf("Target %q not found.", t.GetPublicId())
@@ -1049,14 +1051,22 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
Host: net.JoinHostPort(h, p),
}
var reqs []credential.Request
var vaultReqs []credential.Request
var staticIds []string
var dynCreds []*session.DynamicCredential
for _, l := range libs {
reqs = append(reqs, credential.Request{
SourceId: l.Id(),
Purpose: l.CredentialPurpose(),
})
dynCreds = append(dynCreds, session.NewDynamicCredential(l.Id(), l.CredentialPurpose()))
var staticCreds []*session.StaticCredential
for _, cs := range credSources {
switch cs.Type() {
case target.LibraryCredentialSourceType:
vaultReqs = append(vaultReqs, credential.Request{
SourceId: cs.Id(),
Purpose: cs.CredentialPurpose(),
})
dynCreds = append(dynCreds, session.NewDynamicCredential(cs.Id(), cs.CredentialPurpose()))
case target.StaticCredentialSourceType:
staticIds = append(staticIds, cs.Id())
staticCreds = append(staticCreds, session.NewStaticCredential(cs.Id(), cs.CredentialPurpose()))
}
}
expTime := timestamppb.Now()
@@ -1073,6 +1083,7 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
ConnectionLimit: t.GetSessionConnectionLimit(),
WorkerFilter: t.GetWorkerFilter(),
DynamicCredentials: dynCreds,
StaticCredentials: staticCreds,
}
sess, err := session.New(sessionComposition)
@@ -1088,111 +1099,82 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
return nil, err
}
var cs []credential.Dynamic
if len(reqs) > 0 {
var dynamic []credential.Dynamic
var staticCredsById map[string]credential.Static
if len(vaultReqs) > 0 {
credRepo, err := s.vaultCredRepoFn()
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
cs, err = credRepo.Issue(ctx, sess.GetPublicId(), reqs)
dynamic, err = credRepo.Issue(ctx, sess.GetPublicId(), vaultReqs)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
}
if len(staticIds) > 0 {
credRepo, err := s.staticCredRepoFn()
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
// Remove duplicate requests
staticIds = strutil.RemoveDuplicates(staticIds, false)
creds, err := credRepo.Retrieve(ctx, t.GetScopeId(), staticIds)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
staticCredsById = make(map[string]credential.Static)
for _, c := range creds {
staticCredsById[c.GetPublicId()] = c
}
}
var creds []*pb.SessionCredential
var workerCreds []session.Credential
for _, cred := range cs {
for _, cred := range dynamic {
switch cred.Purpose() {
case credential.EgressPurpose:
m, err := credentialToProto(ctx, cred)
c, err := dynamicToWorkerCredential(ctx, cred)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
data, err := proto.Marshal(m)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("marshalling secret to proto"))
}
workerCreds = append(workerCreds, data)
workerCreds = append(workerCreds, c)
case credential.ApplicationPurpose:
l := cred.Library()
secret := cred.Secret()
// TODO: Access the json directly from the vault response instead of re-marshalling it.
jSecret, err := json.Marshal(secret)
c, err := dynamicToSessionCredential(ctx, cred)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("marshalling secret to json"))
return nil, errors.Wrap(ctx, err, op)
}
var sSecret *structpb.Struct
switch secret.(type) {
case map[string]interface{}:
// In this case we actually have to re-decode it. The proto wrappers
// choke on json.Number and at the time I'm writing this I don't
// have time to write a walk function to dig through with reflect
// and find all json.Numbers and replace them. So we eat the
// inefficiency. So note that we are specifically _not_ using a
// decoder with UseNumber here.
var dSecret map[string]interface{}
if err := json.Unmarshal(jSecret, &dSecret); err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("decoding json for proto marshaling"))
}
sSecret, err = structpb.NewStruct(dSecret)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("creating proto struct for secret"))
}
}
var credType string
var credData *structpb.Struct
if l.CredentialType() != credential.UnspecifiedType {
credType = string(l.CredentialType())
switch c := cred.(type) {
case credential.UserPassword:
credData, err = handlers.ProtoToStruct(
&pb.UserPasswordCredential{
Username: c.Username(),
Password: string(c.Password()),
},
)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("creating proto struct for credential"))
}
default:
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unsupported credential type"))
}
}
creds = append(creds, &pb.SessionCredential{
CredentialLibrary: &pb.CredentialLibrary{
Id: l.GetPublicId(),
Name: l.GetName(),
Description: l.GetDescription(),
CredentialStoreId: l.GetStoreId(),
Type: subtypes.SubtypeFromId(credentialDomain, l.GetPublicId()).String(),
},
CredentialSource: &pb.CredentialSource{
Id: l.GetPublicId(),
Name: l.GetName(),
Description: l.GetDescription(),
CredentialStoreId: l.GetStoreId(),
Type: subtypes.SubtypeFromId(credentialDomain, l.GetPublicId()).String(),
CredentialType: credType,
},
Secret: &pb.SessionSecret{
Raw: base64.StdEncoding.EncodeToString(jSecret),
Decoded: sSecret,
},
Credential: credData,
})
creds = append(creds, c)
default:
return nil, errors.New(ctx, errors.Unknown, op, fmt.Sprintf("unsupported credential purpose %s", cred.Purpose()))
}
}
for _, sc := range staticCreds {
switch sc.CredentialPurpose {
case string(credential.EgressPurpose):
c, err := staticToWorkerCredential(ctx, staticCredsById[sc.CredentialStaticId])
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
workerCreds = append(workerCreds, c)
case string(credential.ApplicationPurpose):
c, err := staticToSessionCredential(ctx, staticCredsById[sc.CredentialStaticId])
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
creds = append(creds, c)
default:
return nil, errors.New(ctx, errors.Unknown, op, fmt.Sprintf("unsupported credential purpose %s", sc.CredentialPurpose))
}
}
if len(workerCreds) > 0 {
// store credentials in repo, worker will request creds when a connection is established
err = sessionRepo.AddSessionCredentials(ctx, sess.ScopeId, sess.PublicId, workerCreds)
@@ -1226,7 +1208,7 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
Scope: authResults.Scope,
CreatedTime: sess.CreateTime.GetTimestamp(),
Type: t.GetType().String(),
AuthorizationToken: string(encodedMarshaledSad),
AuthorizationToken: encodedMarshaledSad,
UserId: authResults.UserId,
HostId: chosenEndpoint.HostId,
HostSetId: chosenEndpoint.SetId,
@@ -1327,7 +1309,9 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st
if err != nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to build target for update: %v.", err)
}
u.SetPublicId(ctx, id)
if err := u.SetPublicId(ctx, id); err != nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set target id: %v.", err)
}
maskManager, err := subtypeRegistry.maskManager(subtype)
if err != nil {
@@ -1668,7 +1652,7 @@ func toProto(ctx context.Context, in target.Target, hostSources []target.HostSou
// ApplicationCredentialLibrariesField is deprecated and should only be populated
// for library type sources
if cs.Type() == "library" {
if cs.Type() == target.LibraryCredentialSourceType {
appCredLibIds = append(appCredLibIds, cs.Id())
appCredLibraries = append(appCredLibraries, &pb.CredentialLibrary{
Id: cs.Id(),
@@ -2168,22 +2152,3 @@ func validateAuthorizeSessionRequest(req *pbs.AuthorizeSessionRequest) error {
}
return nil
}
// credentialToProto converts the strongly typed credential.Credential into a known proto.Message.
func credentialToProto(ctx context.Context, cred credential.Credential) (*serverpb.Credential, error) {
const op = "targets.credentialToProto"
switch c := cred.(type) {
case credential.UserPassword:
return &serverpb.Credential{
Credential: &serverpb.Credential_UserPassword{
UserPassword: &serverpb.UserPassword{
Username: c.Username(),
Password: string(c.Password()),
},
},
}, nil
default:
return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("unsupported credential %T", c))
}
}
@@ -20,6 +20,7 @@ import (
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentiallibraries"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentials"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/targets"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/workers"
"github.com/hashicorp/boundary/internal/db"
@@ -39,7 +40,8 @@ import (
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/hashicorp/boundary/internal/types/scope"
credpb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/credentiallibraries"
credlibpb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/credentiallibraries"
credpb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/credentials"
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets"
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
@@ -99,10 +101,13 @@ func testService(t *testing.T, conn *db.DB, kms *kms.Kms, wrapper wrapping.Wrapp
pluginHostRepoFn := func() (*plugin.Repository, error) {
return plugin.NewRepository(rw, rw, kms, sche, map[string]plgpb.HostPluginServiceClient{})
}
credentialRepoFn := func() (*vault.Repository, error) {
vaultCredRepoFn := func() (*vault.Repository, error) {
return vault.NewRepository(rw, rw, kms, sche)
}
return targets.NewService(context.Background(), kms, repoFn, iamRepoFn, serversRepoFn, sessionRepoFn, pluginHostRepoFn, staticHostRepoFn, credentialRepoFn)
staticCredRepoFn := func() (*credstatic.Repository, error) {
return credstatic.NewRepository(context.Background(), rw, rw, kms)
}
return targets.NewService(context.Background(), kms, repoFn, iamRepoFn, serversRepoFn, sessionRepoFn, pluginHostRepoFn, staticHostRepoFn, vaultCredRepoFn, staticCredRepoFn)
}
func TestGet(t *testing.T) {
@@ -2436,8 +2441,8 @@ func TestSetTargetCredentialSources(t *testing.T) {
resultLibIds []string
}{
{
name: "Set libary on empty target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty libary"),
name: "Set library on empty target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty library"),
setCredentialSources: []string{cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
resultLibIds: []string{cls[1].GetPublicId()},
@@ -2450,14 +2455,14 @@ func TestSetTargetCredentialSources(t *testing.T) {
},
{
name: "Set library on library populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated libary-libary", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated library-library", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setCredentialSources: []string{cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
resultLibIds: []string{cls[1].GetPublicId()},
},
{
name: "Set static on library populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated static-libary", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated static-library", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setCredentialSources: []string{creds[1].GetPublicId()},
resultCredentialSourceIds: []string{creds[1].GetPublicId()},
},
@@ -2813,9 +2818,12 @@ func TestAuthorizeSession(t *testing.T) {
staticHostRepoFn := func() (*static.Repository, error) {
return staticRepo, nil
}
credentialRepoFn := func() (*vault.Repository, error) {
vaultCredRepoFn := func() (*vault.Repository, error) {
return vault.NewRepository(rw, rw, kms, sche)
}
staticCredRepoFn := func() (*credstatic.Repository, error) {
return credstatic.NewRepository(ctx, rw, rw, kms)
}
atRepoFn := func() (*authtoken.Repository, error) {
return authtoken.NewRepository(rw, rw, kms)
}
@@ -2889,15 +2897,15 @@ func TestAuthorizeSession(t *testing.T) {
v.MountPKI(t)
sec, tok := v.CreateToken(t, vault.WithPolicies([]string{"default", "boundary-controller", "pki"}))
store := vault.TestCredentialStore(t, conn, wrapper, proj.GetPublicId(), v.Addr, tok, sec.Auth.Accessor)
credService, err := credentiallibraries.NewService(credentialRepoFn, iamRepoFn)
vaultStore := vault.TestCredentialStore(t, conn, wrapper, proj.GetPublicId(), v.Addr, tok, sec.Auth.Accessor)
credService, err := credentiallibraries.NewService(vaultCredRepoFn, iamRepoFn)
require.NoError(t, err)
clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credpb.CredentialLibrary{
CredentialStoreId: store.GetPublicId(),
clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{
CredentialStoreId: vaultStore.GetPublicId(),
Name: wrapperspb.String("Library Name"),
Description: wrapperspb.String("Library Description"),
Attrs: &credpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credpb.VaultCredentialLibraryAttributes{
Attrs: &credlibpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credlibpb.VaultCredentialLibraryAttributes{
Path: &wrapperspb.StringValue{
Value: path.Join("pki", "issue", "boundary"),
},
@@ -2943,7 +2951,7 @@ func TestAuthorizeSession(t *testing.T) {
},
}
s, err := targets.NewService(ctx, kms, repoFn, iamRepoFn, serversRepoFn, sessionRepoFn, pluginHostRepoFn, staticHostRepoFn, credentialRepoFn)
s, err := targets.NewService(ctx, kms, repoFn, iamRepoFn, serversRepoFn, sessionRepoFn, pluginHostRepoFn, staticHostRepoFn, vaultCredRepoFn, staticCredRepoFn)
require.NoError(t, err)
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
@@ -3013,14 +3021,14 @@ func TestAuthorizeSession(t *testing.T) {
Id: clsResp.GetItem().GetId(),
Name: clsResp.GetItem().GetName().GetValue(),
Description: clsResp.GetItem().GetDescription().GetValue(),
CredentialStoreId: store.GetPublicId(),
CredentialStoreId: vaultStore.GetPublicId(),
Type: vault.Subtype.String(),
},
CredentialSource: &pb.CredentialSource{
Id: clsResp.GetItem().GetId(),
Name: clsResp.GetItem().GetName().GetValue(),
Description: clsResp.GetItem().GetDescription().GetValue(),
CredentialStoreId: store.GetPublicId(),
CredentialStoreId: vaultStore.GetPublicId(),
Type: vault.Subtype.String(),
},
}},
@@ -3085,9 +3093,12 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
staticHostRepoFn := func() (*static.Repository, error) {
return static.NewRepository(rw, rw, kms)
}
credentialRepoFn := func() (*vault.Repository, error) {
vaultCredRepoFn := func() (*vault.Repository, error) {
return vault.NewRepository(rw, rw, kms, sche)
}
staticCredRepoFn := func() (*credstatic.Repository, error) {
return credstatic.NewRepository(ctx, rw, rw, kms)
}
atRepoFn := func() (*authtoken.Repository, error) {
return authtoken.NewRepository(rw, rw, kms)
}
@@ -3112,7 +3123,7 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
_ = iam.TestUserRole(t, conn, r.GetPublicId(), at.GetIamUserId())
_ = iam.TestRoleGrant(t, conn, r.GetPublicId(), "id=*;type=*;actions=*")
s, err := targets.NewService(ctx, kms, repoFn, iamRepoFn, serversRepoFn, sessionRepoFn, pluginHostRepoFn, staticHostRepoFn, credentialRepoFn)
s, err := targets.NewService(ctx, kms, repoFn, iamRepoFn, serversRepoFn, sessionRepoFn, pluginHostRepoFn, staticHostRepoFn, vaultCredRepoFn, staticCredRepoFn)
require.NoError(t, err)
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
@@ -3124,20 +3135,20 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
v.AddKVPolicy(t)
sec, tok := v.CreateToken(t, vault.WithPolicies([]string{"default", "boundary-controller", "secret"}))
store := vault.TestCredentialStore(t, conn, wrapper, proj.GetPublicId(), v.Addr, tok, sec.Auth.Accessor)
credService, err := credentiallibraries.NewService(credentialRepoFn, iamRepoFn)
vaultStore := vault.TestCredentialStore(t, conn, wrapper, proj.GetPublicId(), v.Addr, tok, sec.Auth.Accessor)
credLibService, err := credentiallibraries.NewService(vaultCredRepoFn, iamRepoFn)
require.NoError(t, err)
// Create secret in vault with default username and password fields
defaultUserPass := v.CreateKVSecret(t, "default-userpass", []byte(`{"data": {"username": "my-user", "password": "my-pass"}}`))
require.NotNil(t, defaultUserPass)
clsRespUserPassword, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credpb.CredentialLibrary{
CredentialStoreId: store.GetPublicId(),
clsRespUserPassword, err := credLibService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{
CredentialStoreId: vaultStore.GetPublicId(),
Name: wrapperspb.String("Userpassword Library"),
Description: wrapperspb.String("Userpassword Library Description"),
Attrs: &credpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credpb.VaultCredentialLibraryAttributes{
Attrs: &credlibpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credlibpb.VaultCredentialLibraryAttributes{
Path: wrapperspb.String(path.Join("secret", "data", "default-userpass")),
HttpMethod: wrapperspb.String("GET"),
},
@@ -3146,12 +3157,12 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
}})
require.NoError(t, err)
clsRespUnspecified, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credpb.CredentialLibrary{
CredentialStoreId: store.GetPublicId(),
clsRespUnspecified, err := credLibService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{
CredentialStoreId: vaultStore.GetPublicId(),
Name: wrapperspb.String("Unspecified Library"),
Description: wrapperspb.String("Unspecified Library Description"),
Attrs: &credpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credpb.VaultCredentialLibraryAttributes{
Attrs: &credlibpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credlibpb.VaultCredentialLibraryAttributes{
Path: wrapperspb.String(path.Join("secret", "data", "default-userpass")),
HttpMethod: wrapperspb.String("GET"),
},
@@ -3163,12 +3174,12 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
nonDefaultUserPass := v.CreateKVSecret(t, "non-default-userpass", []byte(`{"data": {"non-default-user": "my-user", "non-default-pass": "my-pass"}}`))
require.NotNil(t, nonDefaultUserPass)
clsRespUserPasswordWithMapping, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credpb.CredentialLibrary{
CredentialStoreId: store.GetPublicId(),
clsRespUserPasswordWithMapping, err := credLibService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{
CredentialStoreId: vaultStore.GetPublicId(),
Name: wrapperspb.String("Userpassword Mapping Library"),
Description: wrapperspb.String("Userpassword Mapping Library Description"),
Attrs: &credpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credpb.VaultCredentialLibraryAttributes{
Attrs: &credlibpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credlibpb.VaultCredentialLibraryAttributes{
Path: wrapperspb.String(path.Join("secret", "data", "non-default-userpass")),
HttpMethod: wrapperspb.String("GET"),
},
@@ -3181,55 +3192,146 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
}})
require.NoError(t, err)
staticStore := credstatic.TestCredentialStore(t, conn, wrapper, proj.GetPublicId())
credService, err := credentials.NewService(staticCredRepoFn, iamRepoFn)
require.NoError(t, err)
credResp, err := credService.CreateCredential(ctx, &pbs.CreateCredentialRequest{Item: &credpb.Credential{
CredentialStoreId: staticStore.GetPublicId(),
Type: credstatic.UsernamePasswordSubtype.String(),
Name: wrapperspb.String("Cred Name"),
Description: wrapperspb.String("Cred Description"),
Attrs: &credpb.Credential_UsernamePasswordAttributes{
UsernamePasswordAttributes: &credpb.UsernamePasswordAttributes{
Username: wrapperspb.String("static-username"),
Password: wrapperspb.String("static-password"),
},
},
}})
require.NoError(t, err)
require.NotNil(t, credResp)
cases := []struct {
name string
hostSourceId string
credLib *credpb.CredentialLibrary
credSourceId string
wantedHostId string
wantedEndpoint string
wantedCredType string
wantedCred *structpb.Struct
wantedCred *pb.SessionCredential
}{
{
name: "unspecified",
name: "vault-unspecified",
hostSourceId: shs.GetPublicId(),
credSourceId: clsRespUnspecified.GetItem().GetId(),
wantedHostId: h.GetPublicId(),
wantedEndpoint: h.GetAddress(),
credLib: clsRespUnspecified.GetItem(),
wantedCred: &pb.SessionCredential{
CredentialLibrary: &pb.CredentialLibrary{
Id: clsRespUnspecified.GetItem().GetId(),
Name: clsRespUnspecified.GetItem().GetName().GetValue(),
Description: clsRespUnspecified.GetItem().GetDescription().GetValue(),
CredentialStoreId: vaultStore.GetPublicId(),
Type: vault.Subtype.String(),
},
CredentialSource: &pb.CredentialSource{
Id: clsRespUnspecified.GetItem().GetId(),
Name: clsRespUnspecified.GetItem().GetName().GetValue(),
Description: clsRespUnspecified.GetItem().GetDescription().GetValue(),
CredentialStoreId: vaultStore.GetPublicId(),
Type: vault.Subtype.String(),
},
},
},
{
name: "userpassword",
name: "vault-userpassword",
hostSourceId: shs.GetPublicId(),
credSourceId: clsRespUserPassword.GetItem().GetId(),
wantedHostId: h.GetPublicId(),
wantedEndpoint: h.GetAddress(),
credLib: clsRespUserPassword.GetItem(),
wantedCred: func() *structpb.Struct {
data := map[string]interface{}{
"username": "my-user",
"password": "my-pass",
}
st, err := structpb.NewStruct(data)
require.NoError(t, err)
return st
}(),
wantedCredType: string(credential.UsernamePasswordType),
wantedCred: &pb.SessionCredential{
CredentialLibrary: &pb.CredentialLibrary{
Id: clsRespUserPassword.GetItem().GetId(),
Name: clsRespUserPassword.GetItem().GetName().GetValue(),
Description: clsRespUserPassword.GetItem().GetDescription().GetValue(),
CredentialStoreId: vaultStore.GetPublicId(),
Type: vault.Subtype.String(),
},
CredentialSource: &pb.CredentialSource{
Id: clsRespUserPassword.GetItem().GetId(),
Name: clsRespUserPassword.GetItem().GetName().GetValue(),
Description: clsRespUserPassword.GetItem().GetDescription().GetValue(),
CredentialStoreId: vaultStore.GetPublicId(),
Type: vault.Subtype.String(),
CredentialType: string(credential.UsernamePasswordType),
},
Credential: func() *structpb.Struct {
data := map[string]interface{}{
"password": "my-pass",
"username": "my-user",
}
st, err := structpb.NewStruct(data)
require.NoError(t, err)
return st
}(),
},
},
{
name: "userpassword-with-mapping",
name: "vault-userpassword-with-mapping",
hostSourceId: shs.GetPublicId(),
credSourceId: clsRespUserPasswordWithMapping.GetItem().GetId(),
wantedHostId: h.GetPublicId(),
wantedEndpoint: h.GetAddress(),
credLib: clsRespUserPasswordWithMapping.GetItem(),
wantedCred: func() *structpb.Struct {
data := map[string]interface{}{
"password": "my-pass",
"username": "my-user",
}
st, err := structpb.NewStruct(data)
require.NoError(t, err)
return st
}(),
wantedCredType: string(credential.UsernamePasswordType),
wantedCred: &pb.SessionCredential{
CredentialLibrary: &pb.CredentialLibrary{
Id: clsRespUserPasswordWithMapping.GetItem().GetId(),
Name: clsRespUserPasswordWithMapping.GetItem().GetName().GetValue(),
Description: clsRespUserPasswordWithMapping.GetItem().GetDescription().GetValue(),
CredentialStoreId: vaultStore.GetPublicId(),
Type: vault.Subtype.String(),
},
CredentialSource: &pb.CredentialSource{
Id: clsRespUserPasswordWithMapping.GetItem().GetId(),
Name: clsRespUserPasswordWithMapping.GetItem().GetName().GetValue(),
Description: clsRespUserPasswordWithMapping.GetItem().GetDescription().GetValue(),
CredentialStoreId: vaultStore.GetPublicId(),
Type: vault.Subtype.String(),
CredentialType: string(credential.UsernamePasswordType),
},
Credential: func() *structpb.Struct {
data := map[string]interface{}{
"password": "my-pass",
"username": "my-user",
}
st, err := structpb.NewStruct(data)
require.NoError(t, err)
return st
}(),
},
},
{
name: "static-userpassword",
hostSourceId: shs.GetPublicId(),
credSourceId: credResp.GetItem().GetId(),
wantedHostId: h.GetPublicId(),
wantedEndpoint: h.GetAddress(),
wantedCred: &pb.SessionCredential{
CredentialSource: &pb.CredentialSource{
Id: credResp.GetItem().GetId(),
Name: credResp.GetItem().GetName().GetValue(),
Description: credResp.GetItem().GetDescription().GetValue(),
CredentialStoreId: staticStore.GetPublicId(),
Type: credstatic.Subtype.String(),
CredentialType: string(credential.UsernamePasswordType),
},
Credential: func() *structpb.Struct {
data := map[string]interface{}{
"password": "static-password",
"username": "static-username",
}
st, err := structpb.NewStruct(data)
require.NoError(t, err)
return st
}(),
},
},
}
@@ -3246,7 +3348,7 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
_, err = s.AddTargetCredentialSources(ctx,
&pbs.AddTargetCredentialSourcesRequest{
Id: tar.GetPublicId(),
ApplicationCredentialSourceIds: []string{tc.credLib.GetId()},
ApplicationCredentialSourceIds: []string{tc.credSourceId},
Version: apiTar.GetItem().GetVersion(),
})
require.NoError(t, err)
@@ -3274,32 +3376,13 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
Description: proj.GetDescription(),
ParentScopeId: proj.GetParentId(),
},
TargetId: tar.GetPublicId(),
UserId: at.GetIamUserId(),
HostSetId: tc.hostSourceId,
HostId: tc.wantedHostId,
Type: "tcp",
Endpoint: fmt.Sprintf("tcp://%s:%d", tc.wantedEndpoint, defaultPort),
Credentials: []*pb.SessionCredential{
{
CredentialLibrary: &pb.CredentialLibrary{
Id: tc.credLib.GetId(),
Name: tc.credLib.GetName().GetValue(),
Description: tc.credLib.GetDescription().GetValue(),
CredentialStoreId: store.GetPublicId(),
Type: vault.Subtype.String(),
},
CredentialSource: &pb.CredentialSource{
Id: tc.credLib.GetId(),
Name: tc.credLib.GetName().GetValue(),
Description: tc.credLib.GetDescription().GetValue(),
CredentialStoreId: store.GetPublicId(),
Type: vault.Subtype.String(),
CredentialType: tc.wantedCredType,
},
Credential: tc.wantedCred,
},
},
TargetId: tar.GetPublicId(),
UserId: at.GetIamUserId(),
HostSetId: tc.hostSourceId,
HostId: tc.wantedHostId,
Type: "tcp",
Endpoint: fmt.Sprintf("tcp://%s:%d", tc.wantedEndpoint, defaultPort),
Credentials: []*pb.SessionCredential{tc.wantedCred},
// TODO: validate the contents of the authorization token is what is expected
}
got := asRes.GetItem()
@@ -3350,15 +3433,18 @@ func TestAuthorizeSession_Errors(t *testing.T) {
pluginHostRepoFn := func() (*plugin.Repository, error) {
return plugin.NewRepository(rw, rw, kms, sche, map[string]plgpb.HostPluginServiceClient{})
}
credentialRepoFn := func() (*vault.Repository, error) {
vaultCredRepoFn := func() (*vault.Repository, error) {
return vault.NewRepository(rw, rw, kms, sche)
}
staticCredRepoFn := func() (*credstatic.Repository, error) {
return credstatic.NewRepository(ctx, rw, rw, kms)
}
atRepoFn := func() (*authtoken.Repository, error) {
return authtoken.NewRepository(rw, rw, kms)
}
org, proj := iam.TestScopes(t, iamRepo)
s, err := targets.NewService(ctx, kms, repoFn, iamRepoFn, serversRepoFn, sessionRepoFn, pluginHostRepoFn, staticHostRepoFn, credentialRepoFn)
s, err := targets.NewService(ctx, kms, repoFn, iamRepoFn, serversRepoFn, sessionRepoFn, pluginHostRepoFn, staticHostRepoFn, vaultCredRepoFn, staticCredRepoFn)
require.NoError(t, err)
// Authorized user gets full permissions
@@ -3441,13 +3527,13 @@ func TestAuthorizeSession_Errors(t *testing.T) {
}
libraryExists := func(tar target.Target) (version uint32) {
credService, err := credentiallibraries.NewService(credentialRepoFn, iamRepoFn)
credService, err := credentiallibraries.NewService(vaultCredRepoFn, iamRepoFn)
require.NoError(t, err)
clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credpb.CredentialLibrary{
clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{
CredentialStoreId: store.GetPublicId(),
Description: wrapperspb.String(fmt.Sprintf("Library Description for target %q", tar.GetName())),
Attrs: &credpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credpb.VaultCredentialLibraryAttributes{
Attrs: &credlibpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credlibpb.VaultCredentialLibraryAttributes{
Path: wrapperspb.String(path.Join("database", "creds", "opened")),
},
},
@@ -3465,13 +3551,13 @@ func TestAuthorizeSession_Errors(t *testing.T) {
}
misConfiguredlibraryExists := func(tar target.Target) (version uint32) {
credService, err := credentiallibraries.NewService(credentialRepoFn, iamRepoFn)
credService, err := credentiallibraries.NewService(vaultCredRepoFn, iamRepoFn)
require.NoError(t, err)
clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credpb.CredentialLibrary{
clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{
CredentialStoreId: store.GetPublicId(),
Description: wrapperspb.String(fmt.Sprintf("Library Description for target %q", tar.GetName())),
Attrs: &credpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credpb.VaultCredentialLibraryAttributes{
Attrs: &credlibpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credlibpb.VaultCredentialLibraryAttributes{
Path: wrapperspb.String("bad path"),
},
},
@@ -40,7 +40,8 @@ begin;
tcl.target_id,
tcl.credential_library_id as credential_source_id,
tcl.credential_purpose,
cl.store_id
cl.store_id,
'library' as type
from
target_credential_library tcl,
credential_library cl
@@ -51,7 +52,8 @@ begin;
tcs.target_id,
tcs.credential_static_id as credential_source_id,
tcs.credential_purpose,
cst.store_id
cst.store_id,
'static' as type
from
target_static_credential tcs,
credential_static cst
@@ -125,6 +125,10 @@ message CredentialSource {
// create_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
timestamp.v1.Timestamp create_time = 40;
// type of credential source (library or static)
// @inject_tag: `gorm:"not_null"`
string type = 50;
}
message CredentialSourceView {
+16 -1
View File
@@ -5,6 +5,15 @@ import (
"github.com/hashicorp/boundary/internal/target/store"
)
// CredentialSourceType is the type of credential source.
type CredentialSourceType string
// Credential source type values.
const (
LibraryCredentialSourceType CredentialSourceType = "library"
StaticCredentialSourceType CredentialSourceType = "static"
)
var _ CredentialSource = (*TargetCredentialSource)(nil)
// CredentialSource is an interface that can be implemented by both a library
@@ -14,10 +23,11 @@ type CredentialSource interface {
Id() string
CredentialPurpose() credential.Purpose
TargetId() string
Type() CredentialSourceType
}
// CredentialSources contains slices of credential publicIds
// per purpose to be attacehd to the target.
// per purpose to be attached to the target.
type CredentialSources struct {
ApplicationCredentialIds []string
EgressCredentialIds []string
@@ -58,6 +68,11 @@ func (ts *TargetCredentialSource) TargetId() string {
return ts.GetTargetId()
}
// Type returns the type of the credential source (library or static)
func (ts *TargetCredentialSource) Type() CredentialSourceType {
return CredentialSourceType(ts.GetType())
}
// credentialSourceView provides a common way to return credential sources regardless of their
// underlying type (library or static).
type credentialSourceView struct {
@@ -478,8 +478,8 @@ func (r *Repository) changes(ctx context.Context, targetId string, ids []string,
if err := r.reader.ScanRows(ctx, rows, &chg); err != nil {
return nil, nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("scan row failed"))
}
switch chg.Type {
case "library":
switch CredentialSourceType(chg.Type) {
case LibraryCredentialSourceType:
lib, err := NewCredentialLibrary(targetId, chg.SourceId, purpose)
if err != nil {
return nil, nil, nil, nil, errors.Wrap(ctx, err, op)
@@ -490,7 +490,7 @@ func (r *Repository) changes(ctx context.Context, targetId string, ids []string,
default:
addCredLib = append(addCredLib, lib)
}
case "static":
case StaticCredentialSourceType:
cred, err := NewStaticCredential(targetId, chg.SourceId, purpose)
if err != nil {
return nil, nil, nil, nil, errors.Wrap(ctx, err, op)
@@ -547,9 +547,9 @@ func (r *Repository) createSources(ctx context.Context, tId string, tSubtype sub
// Create a map between credential source ID and it's type (library or static).
// This will allow for a quick lookup when calling the corresponding New below
credTypeById := make(map[string]string, len(ids))
credTypeById := make(map[string]CredentialSourceType, len(ids))
for _, cv := range credView {
credTypeById[cv.GetPublicId()] = cv.GetType()
credTypeById[cv.GetPublicId()] = CredentialSourceType(cv.GetType())
}
credLibs := make([]*CredentialLibrary, 0, totalCreds)
@@ -561,13 +561,13 @@ func (r *Repository) createSources(ctx context.Context, tId string, tSubtype sub
for purpose, ids := range byPurpose {
for _, id := range ids {
switch credTypeById[id] {
case "library":
case LibraryCredentialSourceType:
lib, err := NewCredentialLibrary(tId, id, purpose)
if err != nil {
return nil, nil, errors.Wrap(ctx, err, op)
}
credLibs = append(credLibs, lib)
case "static":
case StaticCredentialSourceType:
cred, err := NewStaticCredential(tId, id, purpose)
if err != nil {
return nil, nil, errors.Wrap(ctx, err, op)
+23 -11
View File
@@ -427,6 +427,9 @@ type CredentialSource struct {
// create_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
CreateTime *timestamp.Timestamp `protobuf:"bytes,40,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty" gorm:"default:current_timestamp"`
// type of credential source (library or static)
// @inject_tag: `gorm:"not_null"`
Type string `protobuf:"bytes,50,opt,name=type,proto3" json:"type,omitempty" gorm:"not_null"`
}
func (x *CredentialSource) Reset() {
@@ -489,6 +492,13 @@ func (x *CredentialSource) GetCreateTime() *timestamp.Timestamp {
return nil
}
func (x *CredentialSource) GetType() string {
if x != nil {
return x.Type
}
return ""
}
type CredentialSourceView struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -628,7 +638,7 @@ var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22,
0xdd, 0x01, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f,
0xf1, 0x01, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69,
0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49,
0x64, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f,
@@ -641,16 +651,18 @@ var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{
0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22,
0x47, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x75,
0x72, 0x63, 0x65, 0x56, 0x69, 0x65, 0x77, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x14, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x61, 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b,
0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12,
0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74,
0x79, 0x70, 0x65, 0x22, 0x47, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
0x6c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x69, 0x65, 0x77, 0x12, 0x1b, 0x0a, 0x09, 0x70,
0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x42, 0x3b, 0x5a, 0x39,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69,
0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x73, 0x74,
0x6f, 0x72, 0x65, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (