feat(handlers): CRUDL support for static password credential (#6181)

pull/6207/head
Bharath Gajjala 4 months ago
parent ec7450961c
commit 11c4fd7580

@ -179,6 +179,18 @@ func WithJsonCredentialObject(inObject map[string]interface{}) Option {
}
}
func WithPasswordCredentialPassword(inPassword string) Option {
return func(o *options) {
raw, ok := o.postMap["attributes"]
if !ok {
raw = any(map[string]any{})
}
val := raw.(map[string]any)
val["password"] = inPassword
o.postMap["attributes"] = val
}
}
func WithUsernamePasswordCredentialPassword(inPassword string) Option {
return func(o *options) {
raw, ok := o.postMap["attributes"]

@ -0,0 +1,41 @@
// Code generated by "make api"; DO NOT EDIT.
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package credentials
import (
"fmt"
"github.com/mitchellh/mapstructure"
)
type PasswordAttributes struct {
Password string `json:"password,omitempty"`
PasswordHmac string `json:"password_hmac,omitempty"`
}
func AttributesMapToPasswordAttributes(in map[string]any) (*PasswordAttributes, error) {
if in == nil {
return nil, fmt.Errorf("nil input map")
}
var out PasswordAttributes
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
Result: &out,
TagName: "json",
})
if err != nil {
return nil, fmt.Errorf("error creating mapstructure decoder: %w", err)
}
if err := dec.Decode(in); err != nil {
return nil, fmt.Errorf("error decoding: %w", err)
}
return &out, nil
}
func (pt *Credential) GetPasswordAttributes() (*PasswordAttributes, error) {
if pt.Type != "password" {
return nil, fmt.Errorf("asked to fetch %s-type attributes but credential is of type %s", "password", pt.Type)
}
return AttributesMapToPasswordAttributes(pt.Attributes)
}

@ -736,6 +736,22 @@ var inputStructs = []*structInfo{
mapstructureConversionTemplate,
},
},
{
inProto: &credentials.PasswordAttributes{},
outFile: "credentials/password_attributes.gen.go",
subtypeName: "PasswordCredential",
subtype: "password",
fieldOverrides: []fieldInfo{
{
Name: "Password",
SkipDefault: true,
},
},
parentTypeName: "Credential",
templates: []*template.Template{
mapstructureConversionTemplate,
},
},
{
inProto: &credentials.SshPrivateKeyAttributes{},
outFile: "credentials/ssh_private_key_attributes.gen.go",

@ -49,6 +49,7 @@ var (
upMaskManager handlers.MaskManager
spkMaskManager handlers.MaskManager
jsonMaskManager handlers.MaskManager
pMaskmanager handlers.MaskManager
// IdActions contains the set of actions that can be performed on
// individual resources
@ -97,6 +98,13 @@ func init() {
); err != nil {
panic(err)
}
if pMaskmanager, err = handlers.NewMaskManager(
context.Background(),
handlers.MaskDestination{&store.PasswordCredential{}},
handlers.MaskSource{&pb.Credential{}, &pb.PasswordAttributes{}},
); err != nil {
panic(err)
}
// TODO: refactor to remove IdActionsMap and CollectionActions package variables
action.RegisterResource(resource.Credential, IdActions, CollectionActions)
@ -454,6 +462,23 @@ func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.Cred
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to create credential but no error returned from repository.")
}
return out, nil
case credential.PasswordSubtype.String():
cred, err := toPasswordStorageCredential(ctx, item.GetCredentialStoreId(), item)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
repo, err := s.repoFn()
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
out, err := repo.CreatePasswordCredential(ctx, scopeId, cred)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create credential"))
}
if out == nil {
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to create credential but no error returned from repository.")
}
return out, nil
case credential.SshPrivateKeySubtype.String():
cred, err := toSshPrivateKeyStorageCredential(ctx, item.GetCredentialStoreId(), item)
if err != nil {
@ -551,6 +576,29 @@ func (s Service) updateInRepo(
return nil, handlers.NotFoundErrorf("Credential %q doesn't exist or incorrect version provided.", id)
}
return out, nil
case credential.PasswordSubtype:
dbMasks = append(dbMasks, pMaskmanager.Translate(masks)...)
if len(dbMasks) == 0 {
return nil, handlers.InvalidArgumentErrorf("No valid fields included in the update mask.", map[string]string{"update_mask": "No valid fields provided in the update mask."})
}
cred, err := toPasswordStorageCredential(ctx, storeId, in)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to convert to password storage credential"))
}
cred.PublicId = id
repo, err := s.repoFn()
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
out, rowsUpdated, err := repo.UpdatePasswordCredential(ctx, scopeId, cred, item.GetVersion(), dbMasks)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to update credential"))
}
if rowsUpdated == 0 {
return nil, handlers.NotFoundErrorf("Credential %q doesn't exist or incorrect version provided.", id)
}
return out, nil
case credential.SshPrivateKeySubtype:
dbMasks = append(dbMasks, spkMaskManager.Translate(masks)...)
@ -731,6 +779,8 @@ func toProto(in credential.Static, opt ...handlers.Option) (*pb.Credential, erro
out.Type = credential.UsernamePasswordSubtype.String()
case *static.UsernamePasswordDomainCredential:
out.Type = credential.UsernamePasswordDomainSubtype.String()
case *static.PasswordCredential:
out.Type = credential.PasswordSubtype.String()
case *static.SshPrivateKeyCredential:
out.Type = credential.SshPrivateKeySubtype.String()
case *static.JsonCredential:
@ -779,6 +829,14 @@ func toProto(in credential.Static, opt ...handlers.Option) (*pb.Credential, erro
},
}
}
case *static.PasswordCredential:
if outputFields.Has(globals.AttributesField) {
out.Attrs = &pb.Credential_PasswordAttributes{
PasswordAttributes: &pb.PasswordAttributes{
PasswordHmac: base64.RawURLEncoding.EncodeToString(cred.GetPasswordHmac()),
},
}
}
case *static.SshPrivateKeyCredential:
if outputFields.Has(globals.AttributesField) {
out.Attrs = &pb.Credential_SshPrivateKeyAttributes{
@ -848,6 +906,28 @@ func toUsernamePasswordDomainStorageCredential(ctx context.Context, storeId stri
return cs, err
}
func toPasswordStorageCredential(ctx context.Context, storeId string, in *pb.Credential) (out *static.PasswordCredential, err error) {
const op = "credentials.toPasswordStorageCredential"
var opts []static.Option
if in.GetName() != nil {
opts = append(opts, static.WithName(in.GetName().GetValue()))
}
if in.GetDescription() != nil {
opts = append(opts, static.WithDescription(in.GetDescription().GetValue()))
}
attrs := in.GetPasswordAttributes()
cs, err := static.NewPasswordCredential(
storeId,
credential.Password(attrs.GetPassword().GetValue()),
opts...)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to build credential"))
}
return cs, err
}
func toSshPrivateKeyStorageCredential(ctx context.Context, storeId string, in *pb.Credential) (out *static.SshPrivateKeyCredential, err error) {
const op = "credentials.toSshPrivateKeyStorageCredential"
var opts []static.Option
@ -919,6 +999,7 @@ func validateGetRequest(req *pbs.GetCredentialRequest) error {
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
globals.PasswordCredentialPrefix,
globals.SshPrivateKeyCredentialPrefix,
globals.JsonCredentialPrefix,
)
@ -949,6 +1030,10 @@ func validateCreateRequest(req *pbs.CreateCredentialRequest) error {
if req.Item.GetUsernamePasswordDomainAttributes().GetDomain().GetValue() == "" {
badFields[domainField] = "Field required for creating a username-password-domain credential."
}
case credential.PasswordSubtype.String():
if req.Item.GetPasswordAttributes().GetPassword().GetValue() == "" {
badFields[passwordField] = "Field required for creating a password credential."
}
case credential.SshPrivateKeySubtype.String():
if req.Item.GetSshPrivateKeyAttributes().GetUsername().GetValue() == "" {
badFields[usernameField] = "Field required for creating an SSH private key credential."
@ -1018,7 +1103,11 @@ func validateUpdateRequest(req *pbs.UpdateCredentialRequest) error {
if handlers.MaskContains(req.GetUpdateMask().GetPaths(), domainField) && attrs.GetDomain().GetValue() == "" {
badFields[domainField] = "This is a required field and cannot be set to empty."
}
case credential.PasswordSubtype:
attrs := req.GetItem().GetPasswordAttributes()
if handlers.MaskContains(req.GetUpdateMask().GetPaths(), passwordField) && attrs.GetPassword().GetValue() == "" {
badFields[passwordField] = "This is a required field and cannot be set to empty."
}
case credential.SshPrivateKeySubtype:
attrs := req.GetItem().GetSshPrivateKeyAttributes()
if handlers.MaskContains(req.GetUpdateMask().GetPaths(), usernameField) && attrs.GetUsername().GetValue() == "" {
@ -1070,6 +1159,7 @@ func validateUpdateRequest(req *pbs.UpdateCredentialRequest) error {
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
globals.PasswordCredentialPrefix,
globals.SshPrivateKeyCredentialPrefix,
globals.JsonCredentialPrefix,
)
@ -1082,6 +1172,7 @@ func validateDeleteRequest(req *pbs.DeleteCredentialRequest) error {
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
globals.PasswordCredentialPrefix,
globals.SshPrivateKeyCredentialPrefix,
globals.JsonCredentialPrefix,
)

@ -68,7 +68,7 @@ func staticJsonCredentialToProto(cred *static.JsonCredential, prj *iam.Scope, hm
}
}
func staticPasswordCredentialToProto(cred *static.UsernamePasswordCredential, prj *iam.Scope, hmac string) *pb.Credential {
func staticUsernamePasswordCredentialToProto(cred *static.UsernamePasswordCredential, prj *iam.Scope, hmac string) *pb.Credential {
return &pb.Credential{
Id: cred.GetPublicId(),
CredentialStoreId: cred.GetStoreId(),
@ -87,7 +87,25 @@ func staticPasswordCredentialToProto(cred *static.UsernamePasswordCredential, pr
}
}
func staticPasswordDomainCredentialToProto(cred *static.UsernamePasswordDomainCredential, prj *iam.Scope, hmac string) *pb.Credential {
func staticPasswordCredentialToProto(cred *static.PasswordCredential, prj *iam.Scope, hmac string) *pb.Credential {
return &pb.Credential{
Id: cred.GetPublicId(),
CredentialStoreId: cred.GetStoreId(),
Scope: &scopepb.ScopeInfo{Id: prj.GetPublicId(), Type: scope.Project.String(), ParentScopeId: prj.GetParentId()},
CreatedTime: cred.GetCreateTime().GetTimestamp(),
UpdatedTime: cred.GetUpdateTime().GetTimestamp(),
Version: cred.GetVersion(),
Type: credential.PasswordSubtype.String(),
AuthorizedActions: testAuthorizedActions,
Attrs: &pb.Credential_PasswordAttributes{
PasswordAttributes: &pb.PasswordAttributes{
PasswordHmac: base64.RawURLEncoding.EncodeToString([]byte(hmac)),
},
},
}
}
func staticUsernamePasswordDomainCredentialToProto(cred *static.UsernamePasswordDomainCredential, prj *iam.Scope, hmac string) *pb.Credential {
return &pb.Credential{
Id: cred.GetPublicId(),
CredentialStoreId: cred.GetStoreId(),
@ -155,13 +173,18 @@ func TestList(t *testing.T) {
c := static.TestUsernamePasswordCredential(t, conn, wrapper, user, pass, store.GetPublicId(), prj.GetPublicId())
hm, err := crypto.HmacSha256(ctx, []byte(pass), databaseWrapper, []byte(store.GetPublicId()), nil, crypto.WithEd25519())
require.NoError(t, err)
wantCreds = append(wantCreds, staticPasswordCredentialToProto(c, prj, hm))
wantCreds = append(wantCreds, staticUsernamePasswordCredentialToProto(c, prj, hm))
domain := fmt.Sprintf("domain-%d", i)
upd := static.TestUsernamePasswordDomainCredential(t, conn, wrapper, user, pass, domain, store.GetPublicId(), prj.GetPublicId())
hm, err = crypto.HmacSha256(ctx, []byte(pass), databaseWrapper, []byte(store.GetPublicId()), nil, crypto.WithEd25519())
require.NoError(t, err)
wantCreds = append(wantCreds, staticPasswordDomainCredentialToProto(upd, prj, hm))
wantCreds = append(wantCreds, staticUsernamePasswordDomainCredentialToProto(upd, prj, hm))
p := static.TestPasswordCredential(t, conn, wrapper, pass, store.GetPublicId(), prj.GetPublicId())
hm, err = crypto.HmacSha256(ctx, []byte(pass), databaseWrapper, []byte(store.GetPublicId()), nil, crypto.WithEd25519())
require.NoError(t, err)
wantCreds = append(wantCreds, staticPasswordCredentialToProto(p, prj, hm))
spk := static.TestSshPrivateKeyCredential(t, conn, wrapper, user, static.TestSshPrivateKeyPem, store.GetPublicId(), prj.GetPublicId())
hm, err = crypto.HmacSha256(ctx, []byte(static.TestSshPrivateKeyPem), databaseWrapper, []byte(store.GetPublicId()), nil)
@ -193,7 +216,7 @@ func TestList(t *testing.T) {
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 40,
EstItemCount: 50,
},
anonRes: &pbs.ListCredentialsResponse{
Items: wantCreds,
@ -247,9 +270,9 @@ func TestList(t *testing.T) {
},
{
name: "Filter on Attribute",
req: &pbs.ListCredentialsRequest{CredentialStoreId: store.GetPublicId(), Filter: fmt.Sprintf(`"/item/attributes/username"==%q`, wantCreds[4].GetUsernamePasswordAttributes().GetUsername().Value)},
req: &pbs.ListCredentialsRequest{CredentialStoreId: store.GetPublicId(), Filter: fmt.Sprintf(`"/item/attributes/username"==%q`, wantCreds[0].GetUsernamePasswordAttributes().GetUsername().Value)},
res: &pbs.ListCredentialsResponse{
Items: wantCreds[4:7],
Items: []*pb.Credential{wantCreds[0], wantCreds[1], wantCreds[3]},
ResponseType: "complete",
ListToken: "",
SortBy: "created_time",
@ -363,6 +386,10 @@ func TestGet(t *testing.T) {
updHm, err := crypto.HmacSha256(context.Background(), []byte("pass"), databaseWrapper, []byte(store.GetPublicId()), nil, crypto.WithEd25519())
require.NoError(t, err)
pCred := static.TestPasswordCredential(t, conn, wrapper, "pass", store.GetPublicId(), prj.GetPublicId())
pHm, err := crypto.HmacSha256(context.Background(), []byte("pass"), databaseWrapper, []byte(store.GetPublicId()), nil, crypto.WithEd25519())
require.NoError(t, err)
spkCred := static.TestSshPrivateKeyCredential(t, conn, wrapper, "user", static.TestSshPrivateKeyPem, store.GetPublicId(), prj.GetPublicId())
spkHm, err := crypto.HmacSha256(context.Background(), []byte(static.TestSshPrivateKeyPem), databaseWrapper, []byte(store.GetPublicId()), nil)
require.NoError(t, err)
@ -455,7 +482,27 @@ func TestGet(t *testing.T) {
},
},
},
{
name: "success-password-only-credential",
id: pCred.GetPublicId(),
res: &pbs.GetCredentialResponse{
Item: &pb.Credential{
Id: pCred.GetPublicId(),
CredentialStoreId: pCred.GetStoreId(),
Scope: &scopepb.ScopeInfo{Id: store.GetProjectId(), Type: scope.Project.String(), ParentScopeId: prj.GetParentId()},
Type: credential.PasswordSubtype.String(),
AuthorizedActions: testAuthorizedActions,
CreatedTime: pCred.CreateTime.GetTimestamp(),
UpdatedTime: pCred.UpdateTime.GetTimestamp(),
Version: 1,
Attrs: &pb.Credential_PasswordAttributes{
PasswordAttributes: &pb.PasswordAttributes{
PasswordHmac: base64.RawURLEncoding.EncodeToString([]byte(pHm)),
},
},
},
},
},
{
name: "success-spk",
id: spkCred.GetPublicId(),
@ -589,6 +636,7 @@ func TestDelete(t *testing.T) {
upCred := static.TestUsernamePasswordCredential(t, conn, wrapper, "user", "pass", store.GetPublicId(), prj.GetPublicId())
updCred := static.TestUsernamePasswordDomainCredential(t, conn, wrapper, "user", "pass", "domain", store.GetPublicId(), prj.GetPublicId())
pCred := static.TestPasswordCredential(t, conn, wrapper, "pass", store.GetPublicId(), prj.GetPublicId())
spkCred := static.TestSshPrivateKeyCredential(t, conn, wrapper, "user", static.TestSshPrivateKeyPem, store.GetPublicId(), prj.GetPublicId())
obj, _ := static.TestJsonObject(t)
@ -609,6 +657,10 @@ func TestDelete(t *testing.T) {
name: "success-upd",
id: updCred.GetPublicId(),
},
{
name: "success-p",
id: pCred.GetPublicId(),
},
{
name: "success-spk",
id: spkCred.GetPublicId(),
@ -906,6 +958,92 @@ func TestCreate(t *testing.T) {
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Can't specify Id P",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: store.GetPublicId(),
Id: globals.PasswordCredentialPrefix + "_notallowed",
Type: credential.PasswordSubtype.String(),
Attrs: &pb.Credential_PasswordAttributes{
PasswordAttributes: &pb.PasswordAttributes{
Password: wrapperspb.String("password"),
},
},
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Invalid Credential Store Id P",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: "p_invalidid",
Type: credential.PasswordSubtype.String(),
Attrs: &pb.Credential_PasswordAttributes{
PasswordAttributes: &pb.PasswordAttributes{
Password: wrapperspb.String("password"),
},
},
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Can't specify Created Time",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: store.GetPublicId(),
CreatedTime: timestamppb.Now(),
Type: credential.PasswordSubtype.String(),
Attrs: &pb.Credential_PasswordAttributes{
PasswordAttributes: &pb.PasswordAttributes{
Password: wrapperspb.String("password"),
},
},
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Can't specify Updated Time",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: store.GetPublicId(),
UpdatedTime: timestamppb.Now(),
Type: credential.PasswordSubtype.String(),
Attrs: &pb.Credential_PasswordAttributes{
PasswordAttributes: &pb.PasswordAttributes{
Password: wrapperspb.String("password"),
},
},
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Must provide type",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: store.GetPublicId(),
Attrs: &pb.Credential_PasswordAttributes{
PasswordAttributes: &pb.PasswordAttributes{
Password: wrapperspb.String("password"),
},
},
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Must provide password",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: store.GetPublicId(),
Type: credential.PasswordSubtype.String(),
Attrs: &pb.Credential_PasswordAttributes{
PasswordAttributes: &pb.PasswordAttributes{
// Empty password
},
},
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Must provide private key",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
@ -959,6 +1097,32 @@ func TestCreate(t *testing.T) {
},
},
},
{
name: "valid-p",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: store.GetPublicId(),
Type: credential.PasswordSubtype.String(),
Attrs: &pb.Credential_PasswordAttributes{
PasswordAttributes: &pb.PasswordAttributes{
Password: wrapperspb.String("password"),
},
},
}},
idPrefix: globals.PasswordCredentialPrefix + "_",
res: &pbs.CreateCredentialResponse{
Uri: fmt.Sprintf("credentials/%s_", globals.PasswordCredentialPrefix),
Item: &pb.Credential{
Id: store.GetPublicId(),
CredentialStoreId: store.GetPublicId(),
CreatedTime: store.GetCreateTime().GetTimestamp(),
UpdatedTime: store.GetUpdateTime().GetTimestamp(),
Scope: &scopepb.ScopeInfo{Id: prj.GetPublicId(), Type: prj.GetType(), ParentScopeId: prj.GetParentId()},
Version: 1,
Type: credential.PasswordSubtype.String(),
AuthorizedActions: testAuthorizedActions,
},
},
},
{
name: "valid-spk",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
@ -1086,6 +1250,15 @@ func TestCreate(t *testing.T) {
assert.Equal(base64.RawURLEncoding.EncodeToString([]byte(hm)), got.GetItem().GetUsernamePasswordAttributes().GetPasswordHmac())
assert.Empty(got.GetItem().GetUsernamePasswordAttributes().GetPassword())
case credential.PasswordSubtype.String():
password := tc.req.GetItem().GetPasswordAttributes().GetPassword().GetValue()
hm, err := crypto.HmacSha256(ctx, []byte(password), databaseWrapper, []byte(store.GetPublicId()), nil, crypto.WithEd25519())
require.NoError(err)
// Validate attributes equal
assert.Equal(base64.RawURLEncoding.EncodeToString([]byte(hm)), got.GetItem().GetPasswordAttributes().GetPasswordHmac())
assert.Empty(got.GetItem().GetPasswordAttributes().GetPassword())
case credential.SshPrivateKeySubtype.String():
pk := tc.req.GetItem().GetSshPrivateKeyAttributes().GetPrivateKey().GetValue()
hm, err := crypto.HmacSha256(ctx, []byte(pk), databaseWrapper, []byte(store.GetPublicId()), nil)
@ -1193,6 +1366,16 @@ func TestUpdate(t *testing.T) {
return cred, clean
}
freshCredP := func(pass string) (*static.PasswordCredential, func()) {
t.Helper()
cred := static.TestPasswordCredential(t, conn, wrapper, pass, store.GetPublicId(), prj.GetPublicId())
clean := func() {
_, err := s.DeleteCredential(ctx, &pbs.DeleteCredentialRequest{Id: cred.GetPublicId()})
require.NoError(t, err)
}
return cred, clean
}
freshCredSpk := func(user string) (*static.SshPrivateKeyCredential, func()) {
t.Helper()
cred := static.TestSshPrivateKeyCredential(t, conn, wrapper, user, static.TestSshPrivateKeyPem, store.GetPublicId(), prj.GetPublicId())
@ -1405,6 +1588,26 @@ func TestUpdate(t *testing.T) {
return out
},
},
{
name: "update-password-attributes-passwordOnly",
req: &pbs.UpdateCredentialRequest{
UpdateMask: fieldmask("attributes.password"),
Item: &pb.Credential{
Attrs: &pb.Credential_PasswordAttributes{
PasswordAttributes: &pb.PasswordAttributes{
Password: wrapperspb.String("new-password"),
},
},
},
},
res: func(in *pb.Credential) *pb.Credential {
out := proto.Clone(in).(*pb.Credential)
hm, err := crypto.HmacSha256(context.Background(), []byte("new-password"), databaseWrapper, []byte(store.GetPublicId()), nil, crypto.WithEd25519())
require.NoError(t, err)
out.GetPasswordAttributes().PasswordHmac = base64.RawURLEncoding.EncodeToString([]byte(hm))
return out
},
},
{
name: "update-spk",
req: &pbs.UpdateCredentialRequest{
@ -1663,6 +1866,8 @@ func TestUpdate(t *testing.T) {
cred, cleanup = freshCredJson()
} else if strings.Contains(tc.name, "domainupd") {
cred, cleanup = freshCredUpd("user", "pass", "domain")
} else if strings.Contains(tc.name, "passwordOnly") {
cred, cleanup = freshCredP("pass")
} else {
cred, cleanup = freshCredUp("user", "pass")
}
@ -1716,6 +1921,14 @@ func TestUpdate(t *testing.T) {
credUp, cleanUp := freshCredUp("user", "pass")
defer cleanUp()
// cant update read only fields
credUpd, cleanUpd := freshCredUpd("user", "pass", "domain")
defer cleanUpd()
// cant update read only fields
credP, cleanP := freshCredP("pass")
defer cleanP()
newStore := static.TestCredentialStore(t, conn, wrapper, prj.GetPublicId())
roCases := []struct {
@ -1781,6 +1994,42 @@ func TestUpdate(t *testing.T) {
}
matcher(t, gErr)
assert.Nil(t, got)
req = &pbs.UpdateCredentialRequest{
Id: credUpd.GetPublicId(),
Item: tc.item,
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{tc.path}},
}
req.Item.Version = credUpd.Version
got, gErr = s.UpdateCredential(ctx, req)
assert.Error(t, gErr)
matcher = tc.matcher
if matcher == nil {
matcher = func(t *testing.T, e error) {
assert.Truef(t, errors.Is(gErr, handlers.ApiErrorWithCode(codes.InvalidArgument)), "got error %v, wanted invalid argument", gErr)
}
}
matcher(t, gErr)
assert.Nil(t, got)
req = &pbs.UpdateCredentialRequest{
Id: credP.GetPublicId(),
Item: tc.item,
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{tc.path}},
}
req.Item.Version = credP.Version
got, gErr = s.UpdateCredential(ctx, req)
assert.Error(t, gErr)
matcher = tc.matcher
if matcher == nil {
matcher = func(t *testing.T, e error) {
assert.Truef(t, errors.Is(gErr, handlers.ApiErrorWithCode(codes.InvalidArgument)), "got error %v, wanted invalid argument", gErr)
}
}
matcher(t, gErr)
assert.Nil(t, got)
})
}
}
@ -1841,12 +2090,12 @@ func TestListPagination(t *testing.T) {
for _, l := range static.TestUsernamePasswordDomainCredentials(t, conn, wrapper, "username", "password", "domain", credStore.GetPublicId(), prj.PublicId, 5) {
hm, err := crypto.HmacSha256(ctx, []byte("password"), databaseWrapper, []byte(credStore.GetPublicId()), nil, crypto.WithEd25519())
require.NoError(err)
allCredentials = append(allCredentials, staticPasswordDomainCredentialToProto(l, prj, hm))
allCredentials = append(allCredentials, staticUsernamePasswordDomainCredentialToProto(l, prj, hm))
}
for _, l := range static.TestUsernamePasswordCredentials(t, conn, wrapper, "username", "password", credStore.GetPublicId(), prj.PublicId, 5) {
hm, err := crypto.HmacSha256(ctx, []byte("password"), databaseWrapper, []byte(credStore.GetPublicId()), nil, crypto.WithEd25519())
require.NoError(err)
allCredentials = append(allCredentials, staticPasswordCredentialToProto(l, prj, hm))
allCredentials = append(allCredentials, staticUsernamePasswordCredentialToProto(l, prj, hm))
}
// Reverse slices since response is ordered by created_time descending (newest first)

@ -275,6 +275,21 @@ func staticToSessionCredential(ctx context.Context, cred credential.Static) (*pb
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("creating proto struct for username password domain credential"))
}
case *credstatic.PasswordCredential:
var err error
credType = string(globals.PasswordCredentialType)
credData, err = handlers.ProtoToStruct(
ctx,
&pb.PasswordCredential{
Password: string(c.GetPassword()),
},
)
secret = map[string]any{
"password": string(c.GetPassword()),
}
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("creating proto struct for password credential"))
}
case *credstatic.SshPrivateKeyCredential:
var err error
credType = string(globals.SshPrivateKeyCredentialType)
@ -296,7 +311,6 @@ func staticToSessionCredential(ctx context.Context, cred credential.Static) (*pb
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("creating proto struct for ssh private key credential"))
}
case *credstatic.JsonCredential:
var err error
credType = string(globals.JsonCredentialType)

@ -2075,7 +2075,6 @@ func validateAddCredentialSourcesRequest(req *pbs.AddTargetCredentialSourcesRequ
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
globals.PasswordCredentialPrefix,
globals.SshPrivateKeyCredentialPrefix) {
badFields[globals.InjectedApplicationCredentialSourceIdsField] = fmt.Sprintf("Incorrectly formatted credential source identifier %q.", cl)
break
@ -2117,7 +2116,6 @@ func validateSetCredentialSourcesRequest(req *pbs.SetTargetCredentialSourcesRequ
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
globals.PasswordCredentialPrefix,
globals.SshPrivateKeyCredentialPrefix) {
badFields[globals.InjectedApplicationCredentialSourceIdsField] = fmt.Sprintf("Incorrectly formatted credential source identifier %q.", cl)
break
@ -2163,7 +2161,6 @@ func validateRemoveCredentialSourcesRequest(req *pbs.RemoveTargetCredentialSourc
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
globals.PasswordCredentialPrefix,
globals.SshPrivateKeyCredentialPrefix,
globals.JsonCredentialPrefix) {
badFields[globals.InjectedApplicationCredentialSourceIdsField] = fmt.Sprintf("Incorrectly formatted credential source identifier %q.", cl)

@ -3085,6 +3085,7 @@ func TestAddTargetCredentialSources(t *testing.T) {
storeStatic := credstatic.TestCredentialStore(t, conn, wrapper, proj.GetPublicId())
creds := credstatic.TestUsernamePasswordCredentials(t, conn, wrapper, "user", "pass", storeStatic.GetPublicId(), proj.GetPublicId(), 2)
updCreds := credstatic.TestUsernamePasswordDomainCredentials(t, conn, wrapper, "user", "pass", "domain", storeStatic.GetPublicId(), proj.GetPublicId(), 2)
pCreds := credstatic.TestPasswordCredentials(t, conn, wrapper, "pass", storeStatic.GetPublicId(), proj.GetPublicId(), 2)
addCases := []struct {
name string
@ -3110,6 +3111,12 @@ func TestAddTargetCredentialSources(t *testing.T) {
addSources: []string{updCreds[1].GetPublicId()},
resultSourceIds: []string{updCreds[1].GetPublicId()},
},
{
name: "Add static p cred on empty target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty for static_p sources"),
addSources: []string{pCreds[1].GetPublicId()},
resultSourceIds: []string{pCreds[1].GetPublicId()},
},
{
name: "Add library on library populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated for lib-lib sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.BrokeredPurpose, string(cls[0].CredentialType()))})),
@ -3128,6 +3135,12 @@ func TestAddTargetCredentialSources(t *testing.T) {
addSources: []string{cls[1].GetPublicId()},
resultSourceIds: []string{updCreds[0].GetPublicId(), cls[1].GetPublicId()},
},
{
name: "Add library on static p cred populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated for lib-static_p sources", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", pCreds[0].GetPublicId(), credential.BrokeredPurpose)})),
addSources: []string{cls[1].GetPublicId()},
resultSourceIds: []string{pCreds[0].GetPublicId(), cls[1].GetPublicId()},
},
{
name: "Add static cred on library populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated for static-lib sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.BrokeredPurpose, string(cls[0].CredentialType()))})),
@ -3140,6 +3153,12 @@ func TestAddTargetCredentialSources(t *testing.T) {
addSources: []string{updCreds[1].GetPublicId()},
resultSourceIds: []string{cls[0].GetPublicId(), updCreds[1].GetPublicId()},
},
{
name: "Add p static cred on library populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated for static_p-lib sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.BrokeredPurpose, string(cls[0].CredentialType()))})),
addSources: []string{pCreds[1].GetPublicId()},
resultSourceIds: []string{cls[0].GetPublicId(), pCreds[1].GetPublicId()},
},
{
name: "Add static cred on static cred populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated for static-static sources", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.BrokeredPurpose)})),
@ -3152,6 +3171,12 @@ func TestAddTargetCredentialSources(t *testing.T) {
addSources: []string{updCreds[1].GetPublicId()},
resultSourceIds: []string{creds[0].GetPublicId(), updCreds[1].GetPublicId()},
},
{
name: "Add static p cred on static cred populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated for static_p-static sources", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.BrokeredPurpose)})),
addSources: []string{pCreds[1].GetPublicId()},
resultSourceIds: []string{creds[0].GetPublicId(), pCreds[1].GetPublicId()},
},
{
name: "Add duplicated sources on library populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "duplicated for lib sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.BrokeredPurpose, string(cls[0].CredentialType()))})),
@ -3170,6 +3195,12 @@ func TestAddTargetCredentialSources(t *testing.T) {
addSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId(), updCreds[1].GetPublicId(), updCreds[1].GetPublicId()},
resultSourceIds: []string{updCreds[0].GetPublicId(), cls[1].GetPublicId(), updCreds[1].GetPublicId()},
},
{
name: "Add duplicated sources on static p cred populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "duplicated for static p sources", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", pCreds[0].GetPublicId(), credential.BrokeredPurpose)})),
addSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId(), pCreds[1].GetPublicId(), pCreds[1].GetPublicId()},
resultSourceIds: []string{pCreds[0].GetPublicId(), cls[1].GetPublicId(), pCreds[1].GetPublicId()},
},
}
for _, tc := range addCases {
@ -3296,6 +3327,7 @@ func TestSetTargetCredentialSources(t *testing.T) {
storeStatic := credstatic.TestCredentialStore(t, conn, wrapper, proj.GetPublicId())
creds := credstatic.TestUsernamePasswordCredentials(t, conn, wrapper, "user", "pass", storeStatic.GetPublicId(), proj.GetPublicId(), 2)
updCreds := credstatic.TestUsernamePasswordDomainCredentials(t, conn, wrapper, "user", "pass", "domain", storeStatic.GetPublicId(), proj.GetPublicId(), 2)
pCreds := credstatic.TestPasswordCredentials(t, conn, wrapper, "pass", storeStatic.GetPublicId(), proj.GetPublicId(), 2)
setCases := []struct {
name string
@ -3321,6 +3353,12 @@ func TestSetTargetCredentialSources(t *testing.T) {
setCredentialSources: []string{updCreds[1].GetPublicId()},
resultCredentialSourceIds: []string{updCreds[1].GetPublicId()},
},
{
name: "Set static_p on empty target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty static_p"),
setCredentialSources: []string{pCreds[1].GetPublicId()},
resultCredentialSourceIds: []string{pCreds[1].GetPublicId()},
},
{
name: "Set library on library populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated library-library", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.BrokeredPurpose, string(cls[0].CredentialType()))})),
@ -3339,6 +3377,12 @@ func TestSetTargetCredentialSources(t *testing.T) {
setCredentialSources: []string{updCreds[1].GetPublicId()},
resultCredentialSourceIds: []string{updCreds[1].GetPublicId()},
},
{
name: "Set static_p on library populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated static_p-library", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.BrokeredPurpose, string(cls[0].CredentialType()))})),
setCredentialSources: []string{pCreds[1].GetPublicId()},
resultCredentialSourceIds: []string{pCreds[1].GetPublicId()},
},
{
name: "Set library on static populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated library-static", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.BrokeredPurpose)})),
@ -3351,6 +3395,12 @@ func TestSetTargetCredentialSources(t *testing.T) {
setCredentialSources: []string{cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
},
{
name: "Set library on static_p populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated library-static_p", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", pCreds[0].GetPublicId(), credential.BrokeredPurpose)})),
setCredentialSources: []string{cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
},
{
name: "Set static on static populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated static-static", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.BrokeredPurpose)})),
@ -3363,12 +3413,24 @@ func TestSetTargetCredentialSources(t *testing.T) {
setCredentialSources: []string{updCreds[1].GetPublicId()},
resultCredentialSourceIds: []string{updCreds[1].GetPublicId()},
},
{
name: "Set static_p on static populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated static_p-static", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.BrokeredPurpose)})),
setCredentialSources: []string{pCreds[1].GetPublicId()},
resultCredentialSourceIds: []string{pCreds[1].GetPublicId()},
},
{
name: "Set static on static_upd populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated static-static_upd", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", updCreds[0].GetPublicId(), credential.BrokeredPurpose)})),
setCredentialSources: []string{creds[1].GetPublicId()},
resultCredentialSourceIds: []string{creds[1].GetPublicId()},
},
{
name: "Set static on static_p populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "populated static-static_p", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", pCreds[0].GetPublicId(), credential.BrokeredPurpose)})),
setCredentialSources: []string{creds[1].GetPublicId()},
resultCredentialSourceIds: []string{creds[1].GetPublicId()},
},
{
name: "Set duplicate library on populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "duplicate library", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.BrokeredPurpose, string(cls[0].CredentialType()))})),
@ -3387,12 +3449,19 @@ func TestSetTargetCredentialSources(t *testing.T) {
setCredentialSources: []string{updCreds[1].GetPublicId(), updCreds[1].GetPublicId()},
resultCredentialSourceIds: []string{updCreds[1].GetPublicId()},
},
{
name: "Set duplicate static_p on populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "duplicate static_p", target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", pCreds[0].GetPublicId(), credential.BrokeredPurpose)})),
setCredentialSources: []string{pCreds[1].GetPublicId(), pCreds[1].GetPublicId()},
resultCredentialSourceIds: []string{pCreds[1].GetPublicId()},
},
{
name: "Set empty on populated target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "another populated",
target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.BrokeredPurpose, string(cls[0].CredentialType()))}),
target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", creds[0].GetPublicId(), credential.BrokeredPurpose)}),
target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", updCreds[0].GetPublicId(), credential.BrokeredPurpose)}),
target.WithStaticCredentials([]*target.StaticCredential{target.TestNewStaticCredential("", pCreds[0].GetPublicId(), credential.BrokeredPurpose)}),
),
setCredentialSources: []string{},
resultCredentialSourceIds: nil,
@ -3509,6 +3578,7 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
csStatic := credstatic.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
creds := credstatic.TestUsernamePasswordCredentials(t, conn, wrapper, "u", "p", csStatic.GetPublicId(), proj.GetPublicId(), 2)
updCreds := credstatic.TestUsernamePasswordDomainCredentials(t, conn, wrapper, "user", "pass", "domain", csStatic.GetPublicId(), proj.GetPublicId(), 2)
pCreds := credstatic.TestPasswordCredentials(t, conn, wrapper, "pass", csStatic.GetPublicId(), proj.GetPublicId(), 2)
removeCases := []struct {
name string
@ -3535,6 +3605,12 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
removeCredentialSources: []string{updCreds[1].GetPublicId()},
wantErr: true,
},
{
name: "Remove static_p from empty",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "empty static_p"),
removeCredentialSources: []string{pCreds[1].GetPublicId()},
wantErr: true,
},
{
name: "Remove 1 of 2 libraries",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove partial lib",
@ -3565,6 +3641,16 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
removeCredentialSources: []string{updCreds[1].GetPublicId()},
resultCredentialSourceIds: []string{updCreds[0].GetPublicId()},
},
{
name: "Remove 1 of 2 static_p credentials",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove partial static_p",
target.WithStaticCredentials([]*target.StaticCredential{
target.TestNewStaticCredential("", pCreds[0].GetPublicId(), credential.BrokeredPurpose),
target.TestNewStaticCredential("", pCreds[1].GetPublicId(), credential.BrokeredPurpose),
})),
removeCredentialSources: []string{pCreds[1].GetPublicId()},
resultCredentialSourceIds: []string{pCreds[0].GetPublicId()},
},
{
name: "Remove 1 duplicate set of 2 libraries",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove duplicate lib",
@ -3601,6 +3687,19 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
},
resultCredentialSourceIds: []string{updCreds[0].GetPublicId()},
},
{
name: "Remove 1 duplicate set of 2 static_p credentials",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove duplicate static_p",
target.WithStaticCredentials([]*target.StaticCredential{
target.TestNewStaticCredential("", pCreds[0].GetPublicId(), credential.BrokeredPurpose),
target.TestNewStaticCredential("", pCreds[1].GetPublicId(), credential.BrokeredPurpose),
})),
removeCredentialSources: []string{
pCreds[1].GetPublicId(), pCreds[1].GetPublicId(),
},
resultCredentialSourceIds: []string{pCreds[0].GetPublicId()},
},
{
name: "Remove mixed sources from target",
tar: tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), "remove mixed",
@ -3613,12 +3712,14 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
target.TestNewStaticCredential("", creds[1].GetPublicId(), credential.BrokeredPurpose),
target.TestNewStaticCredential("", updCreds[0].GetPublicId(), credential.BrokeredPurpose),
target.TestNewStaticCredential("", updCreds[1].GetPublicId(), credential.BrokeredPurpose),
target.TestNewStaticCredential("", pCreds[0].GetPublicId(), credential.BrokeredPurpose),
target.TestNewStaticCredential("", pCreds[1].GetPublicId(), credential.BrokeredPurpose),
})),
removeCredentialSources: []string{
cls[1].GetPublicId(), creds[0].GetPublicId(), updCreds[0].GetPublicId(),
cls[1].GetPublicId(), creds[0].GetPublicId(), updCreds[0].GetPublicId(), pCreds[0].GetPublicId(),
},
resultCredentialSourceIds: []string{
cls[0].GetPublicId(), creds[1].GetPublicId(), updCreds[1].GetPublicId(),
cls[0].GetPublicId(), creds[1].GetPublicId(), updCreds[1].GetPublicId(), pCreds[1].GetPublicId(),
},
},
{
@ -3633,11 +3734,14 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
target.TestNewStaticCredential("", creds[1].GetPublicId(), credential.BrokeredPurpose),
target.TestNewStaticCredential("", updCreds[0].GetPublicId(), credential.BrokeredPurpose),
target.TestNewStaticCredential("", updCreds[1].GetPublicId(), credential.BrokeredPurpose),
target.TestNewStaticCredential("", pCreds[0].GetPublicId(), credential.BrokeredPurpose),
target.TestNewStaticCredential("", pCreds[1].GetPublicId(), credential.BrokeredPurpose),
})),
removeCredentialSources: []string{
cls[0].GetPublicId(), cls[1].GetPublicId(),
creds[0].GetPublicId(), creds[1].GetPublicId(),
updCreds[0].GetPublicId(), updCreds[1].GetPublicId(),
pCreds[0].GetPublicId(), pCreds[1].GetPublicId(),
},
resultCredentialSourceIds: []string{},
},
@ -4283,6 +4387,20 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, updCredResp)
pCredResp, err := credService.CreateCredential(ctx, &pbs.CreateCredentialRequest{Item: &credpb.Credential{
CredentialStoreId: staticStore.GetPublicId(),
Type: credential.PasswordSubtype.String(),
Name: wrapperspb.String("P Cred Name"),
Description: wrapperspb.String("P Cred Description"),
Attrs: &credpb.Credential_PasswordAttributes{
PasswordAttributes: &credpb.PasswordAttributes{
Password: wrapperspb.String("static-password"),
},
},
}})
require.NoError(t, err)
require.NotNil(t, pCredResp)
sshPkCredResp, err := credService.CreateCredential(ctx, &pbs.CreateCredentialRequest{Item: &credpb.Credential{
CredentialStoreId: staticStore.GetPublicId(),
Type: credential.SshPrivateKeySubtype.String(),
@ -4588,6 +4706,32 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
},
wantedConnectionLimit: 1000,
},
{
name: "static-Password",
hostSourceId: shs.GetPublicId(),
credSourceId: pCredResp.GetItem().GetId(),
wantedHostId: h.GetPublicId(),
wantedEndpoint: h.GetAddress(),
wantedCred: &pb.SessionCredential{
CredentialSource: &pb.CredentialSource{
Id: pCredResp.GetItem().GetId(),
Name: pCredResp.GetItem().GetName().GetValue(),
Description: pCredResp.GetItem().GetDescription().GetValue(),
CredentialStoreId: staticStore.GetPublicId(),
Type: credstatic.Subtype.String(),
CredentialType: string(globals.PasswordCredentialType),
},
Credential: func() *structpb.Struct {
data := map[string]any{
"password": "static-password",
}
st, err := structpb.NewStruct(data)
require.NoError(t, err)
return st
}(),
},
wantedConnectionLimit: 1000,
},
{
name: "static-ssh-private-key",
hostSourceId: shs.GetPublicId(),

@ -82,6 +82,11 @@ message Credential {
(custom_options.v1.generate_sdk_option) = true,
(custom_options.v1.subtype) = "username_password_domain"
];
PasswordAttributes password_attributes = 105 [
(google.api.field_visibility).restriction = "INTERNAL",
(custom_options.v1.generate_sdk_option) = true,
(custom_options.v1.subtype) = "password"
];
}
// Output only. The available actions on this resource for this user.

@ -59,6 +59,7 @@ type Credential struct {
// *Credential_SshPrivateKeyAttributes
// *Credential_JsonAttributes
// *Credential_UsernamePasswordDomainAttributes
// *Credential_PasswordAttributes
Attrs isCredential_Attrs `protobuf_oneof:"attrs"`
// Output only. The available actions on this resource for this user.
AuthorizedActions []string `protobuf:"bytes,300,rep,name=authorized_actions,proto3" json:"authorized_actions,omitempty" class:"public"` // @gotags: `class:"public"`
@ -211,6 +212,15 @@ func (x *Credential) GetUsernamePasswordDomainAttributes() *UsernamePasswordDoma
return nil
}
func (x *Credential) GetPasswordAttributes() *PasswordAttributes {
if x != nil {
if x, ok := x.Attrs.(*Credential_PasswordAttributes); ok {
return x.PasswordAttributes
}
}
return nil
}
func (x *Credential) GetAuthorizedActions() []string {
if x != nil {
return x.AuthorizedActions
@ -243,6 +253,10 @@ type Credential_UsernamePasswordDomainAttributes struct {
UsernamePasswordDomainAttributes *UsernamePasswordDomainAttributes `protobuf:"bytes,104,opt,name=username_password_domain_attributes,json=usernamePasswordDomainAttributes,proto3,oneof"`
}
type Credential_PasswordAttributes struct {
PasswordAttributes *PasswordAttributes `protobuf:"bytes,105,opt,name=password_attributes,json=passwordAttributes,proto3,oneof"`
}
func (*Credential_Attributes) isCredential_Attrs() {}
func (*Credential_UsernamePasswordAttributes) isCredential_Attrs() {}
@ -253,6 +267,8 @@ func (*Credential_JsonAttributes) isCredential_Attrs() {}
func (*Credential_UsernamePasswordDomainAttributes) isCredential_Attrs() {}
func (*Credential_PasswordAttributes) isCredential_Attrs() {}
// The attributes of a UsernamePassword Credential.
type UsernamePasswordAttributes struct {
state protoimpl.MessageState `protogen:"open.v1"`
@ -584,8 +600,7 @@ var File_controller_api_resources_credentials_v1_credential_proto protoreflect.F
const file_controller_api_resources_credentials_v1_credential_proto_rawDesc = "" +
"\n" +
"8controller/api/resources/credentials/v1/credential.proto\x12'controller.api.resources.credentials.v1\x1a.controller/api/resources/scopes/v1/scope.proto\x1a*controller/custom_options/v1/options.proto\x1a\x1bgoogle/api/visibility.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xa5\n" +
"\n" +
"8controller/api/resources/credentials/v1/credential.proto\x12'controller.api.resources.credentials.v1\x1a.controller/api/resources/scopes/v1/scope.proto\x1a*controller/custom_options/v1/options.proto\x1a\x1bgoogle/api/visibility.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xb8\v\n" +
"\n" +
"Credential\x12\x0e\n" +
"\x02id\x18\n" +
@ -610,7 +625,9 @@ const file_controller_api_resources_credentials_v1_credential_proto_rawDesc = ""
"\x0fjson_attributes\x18g \x01(\v27.controller.api.resources.credentials.v1.JsonAttributesB\x1c\xa0\xda)\x01\x9a\xe3)\x04json\xfa\xd2\xe4\x93\x02\n" +
"\x12\bINTERNALH\x00R\x0ejsonAttributes\x12\xcc\x01\n" +
"#username_password_domain_attributes\x18h \x01(\v2I.controller.api.resources.credentials.v1.UsernamePasswordDomainAttributesB0\xa0\xda)\x01\x9a\xe3)\x18username_password_domain\xfa\xd2\xe4\x93\x02\n" +
"\x12\bINTERNALH\x00R usernamePasswordDomainAttributes\x12/\n" +
"\x12\bINTERNALH\x00R usernamePasswordDomainAttributes\x12\x90\x01\n" +
"\x13password_attributes\x18i \x01(\v2;.controller.api.resources.credentials.v1.PasswordAttributesB \xa0\xda)\x01\x9a\xe3)\bpassword\xfa\xd2\xe4\x93\x02\n" +
"\x12\bINTERNALH\x00R\x12passwordAttributes\x12/\n" +
"\x12authorized_actions\x18\xac\x02 \x03(\tR\x12authorized_actionsB\a\n" +
"\x05attrs\"\xb6\x02\n" +
"\x1aUsernamePasswordAttributes\x12a\n" +
@ -694,21 +711,22 @@ var file_controller_api_resources_credentials_v1_credential_proto_depIdxs = []in
4, // 7: controller.api.resources.credentials.v1.Credential.ssh_private_key_attributes:type_name -> controller.api.resources.credentials.v1.SshPrivateKeyAttributes
5, // 8: controller.api.resources.credentials.v1.Credential.json_attributes:type_name -> controller.api.resources.credentials.v1.JsonAttributes
2, // 9: controller.api.resources.credentials.v1.Credential.username_password_domain_attributes:type_name -> controller.api.resources.credentials.v1.UsernamePasswordDomainAttributes
7, // 10: controller.api.resources.credentials.v1.UsernamePasswordAttributes.username:type_name -> google.protobuf.StringValue
7, // 11: controller.api.resources.credentials.v1.UsernamePasswordAttributes.password:type_name -> google.protobuf.StringValue
7, // 12: controller.api.resources.credentials.v1.UsernamePasswordDomainAttributes.username:type_name -> google.protobuf.StringValue
7, // 13: controller.api.resources.credentials.v1.UsernamePasswordDomainAttributes.password:type_name -> google.protobuf.StringValue
7, // 14: controller.api.resources.credentials.v1.UsernamePasswordDomainAttributes.domain:type_name -> google.protobuf.StringValue
7, // 15: controller.api.resources.credentials.v1.PasswordAttributes.password:type_name -> google.protobuf.StringValue
7, // 16: controller.api.resources.credentials.v1.SshPrivateKeyAttributes.username:type_name -> google.protobuf.StringValue
7, // 17: controller.api.resources.credentials.v1.SshPrivateKeyAttributes.private_key:type_name -> google.protobuf.StringValue
7, // 18: controller.api.resources.credentials.v1.SshPrivateKeyAttributes.private_key_passphrase:type_name -> google.protobuf.StringValue
9, // 19: controller.api.resources.credentials.v1.JsonAttributes.object:type_name -> google.protobuf.Struct
20, // [20:20] is the sub-list for method output_type
20, // [20:20] is the sub-list for method input_type
20, // [20:20] is the sub-list for extension type_name
20, // [20:20] is the sub-list for extension extendee
0, // [0:20] is the sub-list for field type_name
3, // 10: controller.api.resources.credentials.v1.Credential.password_attributes:type_name -> controller.api.resources.credentials.v1.PasswordAttributes
7, // 11: controller.api.resources.credentials.v1.UsernamePasswordAttributes.username:type_name -> google.protobuf.StringValue
7, // 12: controller.api.resources.credentials.v1.UsernamePasswordAttributes.password:type_name -> google.protobuf.StringValue
7, // 13: controller.api.resources.credentials.v1.UsernamePasswordDomainAttributes.username:type_name -> google.protobuf.StringValue
7, // 14: controller.api.resources.credentials.v1.UsernamePasswordDomainAttributes.password:type_name -> google.protobuf.StringValue
7, // 15: controller.api.resources.credentials.v1.UsernamePasswordDomainAttributes.domain:type_name -> google.protobuf.StringValue
7, // 16: controller.api.resources.credentials.v1.PasswordAttributes.password:type_name -> google.protobuf.StringValue
7, // 17: controller.api.resources.credentials.v1.SshPrivateKeyAttributes.username:type_name -> google.protobuf.StringValue
7, // 18: controller.api.resources.credentials.v1.SshPrivateKeyAttributes.private_key:type_name -> google.protobuf.StringValue
7, // 19: controller.api.resources.credentials.v1.SshPrivateKeyAttributes.private_key_passphrase:type_name -> google.protobuf.StringValue
9, // 20: controller.api.resources.credentials.v1.JsonAttributes.object:type_name -> google.protobuf.Struct
21, // [21:21] is the sub-list for method output_type
21, // [21:21] is the sub-list for method input_type
21, // [21:21] is the sub-list for extension type_name
21, // [21:21] is the sub-list for extension extendee
0, // [0:21] is the sub-list for field type_name
}
func init() { file_controller_api_resources_credentials_v1_credential_proto_init() }
@ -722,6 +740,7 @@ func file_controller_api_resources_credentials_v1_credential_proto_init() {
(*Credential_SshPrivateKeyAttributes)(nil),
(*Credential_JsonAttributes)(nil),
(*Credential_UsernamePasswordDomainAttributes)(nil),
(*Credential_PasswordAttributes)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{

Loading…
Cancel
Save