feat(handlers): CRUDL support for static Username-Password-Domain credentials

This commit is contained in:
Andrew Gaffney authored and irenarindos committed 2025-09-02 15:12:20 -04:00
1 parent e4dfa76c8e
commit f265ec4e5b
7 files changed
+724 -52

No files matched your search

@@ -37,6 +37,7 @@ import (
const (
usernameField = "attributes.username"
passwordField = "attributes.password"
domainField = "attributes.domain"
privateKeyField = "attributes.private_key"
privateKeyPassphraseField = "attributes.private_key_passphrase"
objectField = "attributes.object"
@@ -44,6 +45,7 @@ const (
)
var (
updMaskManager handlers.MaskManager
upMaskManager handlers.MaskManager
spkMaskManager handlers.MaskManager
jsonMaskManager handlers.MaskManager
@@ -88,6 +90,13 @@ func init() {
); err != nil {
panic(err)
}
if updMaskManager, err = handlers.NewMaskManager(
context.Background(),
handlers.MaskDestination{&store.UsernamePasswordDomainCredential{}},
handlers.MaskSource{&pb.Credential{}, &pb.UsernamePasswordDomainAttributes{}},
); err != nil {
panic(err)
}
// TODO: refactor to remove IdActionsMap and CollectionActions package variables
action.RegisterResource(resource.Credential, IdActions, CollectionActions)
@@ -428,6 +437,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.UsernamePasswordDomainSubtype.String():
cred, err := toUsernamePasswordDomainStorageCredential(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.CreateUsernamePasswordDomainCredential(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 {
@@ -502,6 +528,29 @@ func (s Service) updateInRepo(
return nil, handlers.NotFoundErrorf("Credential %q doesn't exist or incorrect version provided.", id)
}
return out, nil
case credential.UsernamePasswordDomainSubtype:
dbMasks = append(dbMasks, updMaskManager.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 := toUsernamePasswordDomainStorageCredential(ctx, storeId, in)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to convert to username/password/domain storage credential"))
}
cred.PublicId = id
repo, err := s.repoFn()
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
out, rowsUpdated, err := repo.UpdateUsernamePasswordDomainCredential(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)...)
@@ -680,6 +729,8 @@ func toProto(in credential.Static, opt ...handlers.Option) (*pb.Credential, erro
switch in.(type) {
case *static.UsernamePasswordCredential:
out.Type = credential.UsernamePasswordSubtype.String()
case *static.UsernamePasswordDomainCredential:
out.Type = credential.UsernamePasswordDomainSubtype.String()
case *static.SshPrivateKeyCredential:
out.Type = credential.SshPrivateKeySubtype.String()
case *static.JsonCredential:
@@ -718,6 +769,16 @@ func toProto(in credential.Static, opt ...handlers.Option) (*pb.Credential, erro
},
}
}
case *static.UsernamePasswordDomainCredential:
if outputFields.Has(globals.AttributesField) {
out.Attrs = &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String(cred.GetUsername()),
PasswordHmac: base64.RawURLEncoding.EncodeToString(cred.GetPasswordHmac()),
Domain: wrapperspb.String(cred.GetDomain()),
},
}
}
case *static.SshPrivateKeyCredential:
if outputFields.Has(globals.AttributesField) {
out.Attrs = &pb.Credential_SshPrivateKeyAttributes{
@@ -763,6 +824,30 @@ func toUsernamePasswordStorageCredential(ctx context.Context, storeId string, in
return cs, err
}
func toUsernamePasswordDomainStorageCredential(ctx context.Context, storeId string, in *pb.Credential) (out *static.UsernamePasswordDomainCredential, err error) {
const op = "credentials.toUsernamePasswordDomainStorageCredential"
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.GetUsernamePasswordDomainAttributes()
cs, err := static.NewUsernamePasswordDomainCredential(
storeId,
attrs.GetUsername().GetValue(),
credential.Password(attrs.GetPassword().GetValue()),
attrs.GetDomain().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
@@ -833,6 +918,7 @@ func validateGetRequest(req *pbs.GetCredentialRequest) error {
req,
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
globals.SshPrivateKeyCredentialPrefix,
globals.JsonCredentialPrefix,
)
@@ -853,7 +939,16 @@ func validateCreateRequest(req *pbs.CreateCredentialRequest) error {
if req.Item.GetUsernamePasswordAttributes().GetPassword().GetValue() == "" {
badFields[passwordField] = "Field required for creating a username-password credential."
}
case credential.UsernamePasswordDomainSubtype.String():
if req.Item.GetUsernamePasswordDomainAttributes().GetUsername().GetValue() == "" {
badFields[usernameField] = "Field required for creating a username-password-domain credential."
}
if req.Item.GetUsernamePasswordDomainAttributes().GetPassword().GetValue() == "" {
badFields[passwordField] = "Field required for creating a username-password-domain credential."
}
if req.Item.GetUsernamePasswordDomainAttributes().GetDomain().GetValue() == "" {
badFields[domainField] = "Field required for creating a username-password-domain credential."
}
case credential.SshPrivateKeySubtype.String():
if req.Item.GetSshPrivateKeyAttributes().GetUsername().GetValue() == "" {
badFields[usernameField] = "Field required for creating an SSH private key credential."
@@ -912,6 +1007,18 @@ func validateUpdateRequest(req *pbs.UpdateCredentialRequest) error {
badFields[passwordField] = "This is a required field and cannot be set to empty."
}
case credential.UsernamePasswordDomainSubtype:
attrs := req.GetItem().GetUsernamePasswordDomainAttributes()
if handlers.MaskContains(req.GetUpdateMask().GetPaths(), usernameField) && attrs.GetUsername().GetValue() == "" {
badFields[usernameField] = "This is a required field and cannot be set to empty."
}
if handlers.MaskContains(req.GetUpdateMask().GetPaths(), passwordField) && attrs.GetPassword().GetValue() == "" {
badFields[passwordField] = "This is a required field and cannot be set to empty."
}
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.SshPrivateKeySubtype:
attrs := req.GetItem().GetSshPrivateKeyAttributes()
if handlers.MaskContains(req.GetUpdateMask().GetPaths(), usernameField) && attrs.GetUsername().GetValue() == "" {
@@ -962,6 +1069,7 @@ func validateUpdateRequest(req *pbs.UpdateCredentialRequest) error {
},
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
globals.SshPrivateKeyCredentialPrefix,
globals.JsonCredentialPrefix,
)
@@ -973,6 +1081,7 @@ func validateDeleteRequest(req *pbs.DeleteCredentialRequest) error {
req,
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
globals.SshPrivateKeyCredentialPrefix,
globals.JsonCredentialPrefix,
)
@@ -87,6 +87,26 @@ func staticPasswordCredentialToProto(cred *static.UsernamePasswordCredential, pr
}
}
func staticPasswordDomainCredentialToProto(cred *static.UsernamePasswordDomainCredential, 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.UsernamePasswordDomainSubtype.String(),
AuthorizedActions: testAuthorizedActions,
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String(cred.GetUsername()),
PasswordHmac: base64.RawURLEncoding.EncodeToString([]byte(hmac)),
Domain: wrapperspb.String(cred.GetDomain()),
},
},
}
}
func staticSshCredentialToProto(cred *static.SshPrivateKeyCredential, prj *iam.Scope, hmac string) *pb.Credential {
return &pb.Credential{
Id: cred.GetPublicId(),
@@ -137,6 +157,12 @@ func TestList(t *testing.T) {
require.NoError(t, err)
wantCreds = append(wantCreds, staticPasswordCredentialToProto(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))
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)
require.NoError(t, err)
@@ -167,7 +193,7 @@ func TestList(t *testing.T) {
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 30,
EstItemCount: 40,
},
anonRes: &pbs.ListCredentialsResponse{
Items: wantCreds,
@@ -221,15 +247,15 @@ func TestList(t *testing.T) {
},
{
name: "Filter on Attribute",
req: &pbs.ListCredentialsRequest{CredentialStoreId: store.GetPublicId(), Filter: fmt.Sprintf(`"/item/attributes/username"==%q`, wantCreds[3].GetUsernamePasswordAttributes().GetUsername().Value)},
req: &pbs.ListCredentialsRequest{CredentialStoreId: store.GetPublicId(), Filter: fmt.Sprintf(`"/item/attributes/username"==%q`, wantCreds[4].GetUsernamePasswordAttributes().GetUsername().Value)},
res: &pbs.ListCredentialsResponse{
Items: wantCreds[3:5],
Items: wantCreds[4:7],
ResponseType: "complete",
ListToken: "",
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 2,
EstItemCount: 3,
},
anonRes: &pbs.ListCredentialsResponse{
ResponseType: "complete",
@@ -333,6 +359,10 @@ func TestGet(t *testing.T) {
upHm, err := crypto.HmacSha256(context.Background(), []byte("pass"), databaseWrapper, []byte(store.GetPublicId()), nil, crypto.WithEd25519())
require.NoError(t, err)
updCred := static.TestUsernamePasswordDomainCredential(t, conn, wrapper, "user", "pass", "domain", store.GetPublicId(), prj.GetPublicId())
updHm, 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)
@@ -402,6 +432,30 @@ func TestGet(t *testing.T) {
},
},
},
{
name: "success-upd",
id: updCred.GetPublicId(),
res: &pbs.GetCredentialResponse{
Item: &pb.Credential{
Id: updCred.GetPublicId(),
CredentialStoreId: updCred.GetStoreId(),
Scope: &scopepb.ScopeInfo{Id: store.GetProjectId(), Type: scope.Project.String(), ParentScopeId: prj.GetParentId()},
Type: credential.UsernamePasswordDomainSubtype.String(),
AuthorizedActions: testAuthorizedActions,
CreatedTime: updCred.CreateTime.GetTimestamp(),
UpdatedTime: updCred.UpdateTime.GetTimestamp(),
Version: 1,
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String("user"),
PasswordHmac: base64.RawURLEncoding.EncodeToString([]byte(updHm)),
Domain: wrapperspb.String("domain"),
},
},
},
},
},
{
name: "success-spk",
id: spkCred.GetPublicId(),
@@ -534,6 +588,7 @@ func TestDelete(t *testing.T) {
require.NoError(t, err)
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())
spkCred := static.TestSshPrivateKeyCredential(t, conn, wrapper, "user", static.TestSshPrivateKeyPem, store.GetPublicId(), prj.GetPublicId())
obj, _ := static.TestJsonObject(t)
@@ -550,6 +605,10 @@ func TestDelete(t *testing.T) {
name: "success-up",
id: upCred.GetPublicId(),
},
{
name: "success-upd",
id: updCred.GetPublicId(),
},
{
name: "success-spk",
id: spkCred.GetPublicId(),
@@ -654,6 +713,7 @@ func TestCreate(t *testing.T) {
Attrs: &pb.Credential_UsernamePasswordAttributes{
UsernamePasswordAttributes: &pb.UsernamePasswordAttributes{
Username: wrapperspb.String("username"),
Password: wrapperspb.String("password"),
},
},
}},
@@ -718,6 +778,134 @@ func TestCreate(t *testing.T) {
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Can't specify Id UPD",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: store.GetPublicId(),
Id: globals.UsernamePasswordDomainCredentialPrefix + "_notallowed",
Type: credential.UsernamePasswordDomainSubtype.String(),
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String("username"),
Password: wrapperspb.String("password"),
Domain: wrapperspb.String("domain"),
},
},
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Invalid Credential Store Id UPD",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: "p_invalidid",
Type: credential.UsernamePasswordDomainSubtype.String(),
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String("username"),
Password: wrapperspb.String("password"),
Domain: wrapperspb.String("domain"),
},
},
}},
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.UsernamePasswordDomainSubtype.String(),
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String("username"),
Password: wrapperspb.String("password"),
Domain: wrapperspb.String("domain"),
},
},
}},
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.UsernamePasswordDomainSubtype.String(),
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String("username"),
Password: wrapperspb.String("password"),
Domain: wrapperspb.String("domain"),
},
},
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Must provide type",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: store.GetPublicId(),
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String("username"),
Password: wrapperspb.String("password"),
Domain: wrapperspb.String("domain"),
},
},
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Must provide username",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: store.GetPublicId(),
Type: credential.UsernamePasswordDomainSubtype.String(),
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Password: wrapperspb.String("password"),
Domain: wrapperspb.String("domain"),
},
},
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Must provide password",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: store.GetPublicId(),
Type: credential.UsernamePasswordDomainSubtype.String(),
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String("username"),
Domain: wrapperspb.String("domain"),
},
},
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Must provide domain",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
CredentialStoreId: store.GetPublicId(),
Type: credential.UsernamePasswordDomainSubtype.String(),
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String("username"),
Password: wrapperspb.String("password"),
},
},
}},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Must provide private key",
req: &pbs.CreateCredentialRequest{Item: &pb.Credential{
@@ -995,6 +1183,16 @@ func TestUpdate(t *testing.T) {
return cred, clean
}
freshCredUpd := func(user, pass, domain string) (*static.UsernamePasswordDomainCredential, func()) {
t.Helper()
cred := static.TestUsernamePasswordDomainCredential(t, conn, wrapper, user, pass, domain, 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())
@@ -1113,6 +1311,24 @@ func TestUpdate(t *testing.T) {
return out
},
},
{
name: "update-username-domainupd",
req: &pbs.UpdateCredentialRequest{
UpdateMask: fieldmask("attributes.username"),
Item: &pb.Credential{
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String("new-user-name"),
},
},
},
},
res: func(in *pb.Credential) *pb.Credential {
out := proto.Clone(in).(*pb.Credential)
out.GetUsernamePasswordDomainAttributes().Username = wrapperspb.String("new-user-name")
return out
},
},
{
name: "update-username-spk",
req: &pbs.UpdateCredentialRequest{
@@ -1151,6 +1367,44 @@ func TestUpdate(t *testing.T) {
return out
},
},
{
name: "update-password-domainupd",
req: &pbs.UpdateCredentialRequest{
UpdateMask: fieldmask("attributes.password"),
Item: &pb.Credential{
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
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.GetUsernamePasswordDomainAttributes().PasswordHmac = base64.RawURLEncoding.EncodeToString([]byte(hm))
return out
},
},
{
name: "update-domain-domainupd",
req: &pbs.UpdateCredentialRequest{
UpdateMask: fieldmask("attributes.domain"),
Item: &pb.Credential{
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Domain: wrapperspb.String("new-domain"),
},
},
},
},
res: func(in *pb.Credential) *pb.Credential {
out := proto.Clone(in).(*pb.Credential)
out.GetUsernamePasswordDomainAttributes().Domain = wrapperspb.String("new-domain")
return out
},
},
{
name: "update-spk",
req: &pbs.UpdateCredentialRequest{
@@ -1195,6 +1449,56 @@ func TestUpdate(t *testing.T) {
return out
},
},
{
name: "update-username-password-domainupd",
req: &pbs.UpdateCredentialRequest{
UpdateMask: fieldmask("attributes.username", "attributes.password"),
Item: &pb.Credential{
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String("new-username"),
Password: wrapperspb.String("new-password"),
},
},
},
},
res: func(in *pb.Credential) *pb.Credential {
out := proto.Clone(in).(*pb.Credential)
out.GetUsernamePasswordDomainAttributes().Username = wrapperspb.String("new-username")
hm, err := crypto.HmacSha256(context.Background(), []byte("new-password"), databaseWrapper, []byte(store.GetPublicId()), nil, crypto.WithEd25519())
require.NoError(t, err)
out.GetUsernamePasswordDomainAttributes().PasswordHmac = base64.RawURLEncoding.EncodeToString([]byte(hm))
return out
},
},
{
name: "update-username-password-and-domain-domainupd",
req: &pbs.UpdateCredentialRequest{
UpdateMask: fieldmask("attributes.username", "attributes.password", "attributes.domain"),
Item: &pb.Credential{
Attrs: &pb.Credential_UsernamePasswordDomainAttributes{
UsernamePasswordDomainAttributes: &pb.UsernamePasswordDomainAttributes{
Username: wrapperspb.String("new-username"),
Password: wrapperspb.String("new-password"),
Domain: wrapperspb.String("new-domain"),
},
},
},
},
res: func(in *pb.Credential) *pb.Credential {
out := proto.Clone(in).(*pb.Credential)
out.GetUsernamePasswordDomainAttributes().Username = wrapperspb.String("new-username")
hm, err := crypto.HmacSha256(context.Background(), []byte("new-password"), databaseWrapper, []byte(store.GetPublicId()), nil, crypto.WithEd25519())
require.NoError(t, err)
out.GetUsernamePasswordDomainAttributes().Domain = wrapperspb.String("new-domain")
out.GetUsernamePasswordDomainAttributes().PasswordHmac = base64.RawURLEncoding.EncodeToString([]byte(hm))
return out
},
},
{
name: "update-username-and-spk",
req: &pbs.UpdateCredentialRequest{
@@ -1357,6 +1661,8 @@ func TestUpdate(t *testing.T) {
cred, cleanup = freshCredSpk("user")
} else if strings.Contains(tc.name, "json") {
cred, cleanup = freshCredJson()
} else if strings.Contains(tc.name, "domainupd") {
cred, cleanup = freshCredUpd("user", "pass", "domain")
} else {
cred, cleanup = freshCredUp("user", "pass")
}
@@ -1532,6 +1838,11 @@ func TestListPagination(t *testing.T) {
require.NoError(err)
allCredentials = append(allCredentials, staticSshCredentialToProto(l, prj, hm))
}
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))
}
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)
@@ -1592,7 +1903,7 @@ func TestListPagination(t *testing.T) {
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 15,
EstItemCount: 20,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -1618,7 +1929,7 @@ func TestListPagination(t *testing.T) {
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 15,
EstItemCount: 20,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -1630,10 +1941,10 @@ func TestListPagination(t *testing.T) {
// Request rest of results
req.ListToken = got.ListToken
req.PageSize = 15
req.PageSize = 16
got, err = s.ListCredentials(ctx, req)
require.NoError(err)
require.Len(got.GetItems(), 11)
require.Len(got.GetItems(), 16)
// Compare without comparing the list token
assert.Empty(
cmp.Diff(
@@ -1645,7 +1956,7 @@ func TestListPagination(t *testing.T) {
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 15,
EstItemCount: 20,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -1714,7 +2025,7 @@ func TestListPagination(t *testing.T) {
SortDir: "desc",
// Should contain the deleted credential
RemovedIds: []string{deletedCred.Id},
EstItemCount: 15,
EstItemCount: 20,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -1738,7 +2049,7 @@ func TestListPagination(t *testing.T) {
SortBy: "updated_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 15,
EstItemCount: 20,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -1767,7 +2078,7 @@ func TestListPagination(t *testing.T) {
SortDir: "desc",
// Should be empty again
RemovedIds: nil,
EstItemCount: 15,
EstItemCount: 20,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -1791,7 +2102,7 @@ func TestListPagination(t *testing.T) {
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 15,
EstItemCount: 20,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b