feat(handlers/credentiallibraries): Support Vault LDAP credential library

This commit is contained in:
Hugo authored and Danielle Miu committed 2025-11-05 16:20:44 -05:00
1 parent 9e08eafcff
commit 84dd5543cf
8 files changed
+820 -91

No files matched your search

+12
View File
@@ -383,6 +383,18 @@ func WithVaultCredentialLibraryPath(inPath string) Option {
}
}
func WithVaultLdapCredentialLibraryPath(inPath string) Option {
return func(o *options) {
raw, ok := o.postMap["attributes"]
if !ok {
raw = any(map[string]any{})
}
val := raw.(map[string]any)
val["path"] = inPath
o.postMap["attributes"] = val
}
}
func WithVaultSSHCertificateCredentialLibraryPath(inPath string) Option {
return func(o *options) {
raw, ok := o.postMap["attributes"]
@@ -0,0 +1,40 @@
// Code generated by "make api"; DO NOT EDIT.
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package credentiallibraries
import (
"fmt"
"github.com/mitchellh/mapstructure"
)
type VaultLdapCredentialLibraryAttributes struct {
Path string `json:"path,omitempty"`
}
func AttributesMapToVaultLdapCredentialLibraryAttributes(in map[string]any) (*VaultLdapCredentialLibraryAttributes, error) {
if in == nil {
return nil, fmt.Errorf("nil input map")
}
var out VaultLdapCredentialLibraryAttributes
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 *CredentialLibrary) GetVaultLdapCredentialLibraryAttributes() (*VaultLdapCredentialLibraryAttributes, error) {
if pt.Type != "vault-ldap" {
return nil, fmt.Errorf("asked to fetch %s-type attributes but credential-library is of type %s", "vault-ldap", pt.Type)
}
return AttributesMapToVaultLdapCredentialLibraryAttributes(pt.Attributes)
}
+16
View File
@@ -641,6 +641,22 @@ var inputStructs = []*structInfo{
mapstructureConversionTemplate,
},
},
{
inProto: &credentiallibraries.VaultLdapCredentialLibraryAttributes{},
outFile: "credentiallibraries/vault_ldap_credential_library_attributes.gen.go",
subtypeName: "VaultLdapCredentialLibrary",
subtype: "vault-ldap",
fieldOverrides: []fieldInfo{
{
Name: "Path",
SkipDefault: true,
},
},
parentTypeName: "CredentialLibrary",
templates: []*template.Template{
mapstructureConversionTemplate,
},
},
{
inProto: &credentiallibraries.CredentialLibrary{},
outFile: "credentiallibraries/credential_library.gen.go",
@@ -60,6 +60,7 @@ const (
var (
maskManager handlers.MaskManager
sshCertMaskManager handlers.MaskManager
ldapMaskManager handlers.MaskManager
// IdActions contains the set of actions that can be performed on
// individual resources
@@ -107,6 +108,13 @@ func init() {
); err != nil {
panic(err)
}
if ldapMaskManager, err = handlers.NewMaskManager(
context.Background(),
handlers.MaskDestination{&store.LdapCredentialLibrary{}},
handlers.MaskSource{&pb.CredentialLibrary{}, &pb.VaultLdapCredentialLibraryAttributes{}},
); err != nil {
panic(err)
}
// TODO: refactor to remove IdActionsMap and CollectionActions package variables
action.RegisterResource(resource.CredentialLibrary, IdActions, CollectionActions)
@@ -366,19 +374,27 @@ func (s Service) UpdateCredentialLibrary(ctx context.Context, req *pbs.UpdateCre
var currentCredentialType globals.CredentialType
var mo vault.MappingOverride
switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype {
case vault.SSHCertificateLibrarySubtype:
cur, err := repo.LookupSSHCertificateCredentialLibrary(ctx, req.Id)
if err != nil {
return nil, err
}
currentCredentialType = globals.CredentialType(cur.GetCredentialType())
default:
case vault.GenericLibrarySubtype:
cur, err := repo.LookupCredentialLibrary(ctx, req.Id)
if err != nil {
return nil, err
}
currentCredentialType = globals.CredentialType(cur.GetCredentialType())
mo = cur.MappingOverride
case vault.SSHCertificateLibrarySubtype:
cur, err := repo.LookupSSHCertificateCredentialLibrary(ctx, req.Id)
if err != nil {
return nil, err
}
currentCredentialType = globals.CredentialType(cur.GetCredentialType())
case vault.LdapCredentialLibrarySubtype:
cur, err := repo.LookupLdapCredentialLibrary(ctx, req.GetId())
if err != nil {
return nil, err
}
currentCredentialType = globals.CredentialType(cur.GetCredentialType())
default:
return nil, errors.New(ctx, errors.InvalidParameter, op, "unknown vault credential library subtype")
}
if err := validateUpdateRequest(req, currentCredentialType); err != nil {
@@ -456,6 +472,15 @@ func (s Service) getFromRepo(ctx context.Context, id string) (credential.Library
return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("ssh certificate credential library %q not found", id))
}
return cs, err
case vault.LdapCredentialLibrarySubtype:
cs, err := repo.LookupLdapCredentialLibrary(ctx, id)
if err != nil && !errors.IsNotFoundError(err) {
return nil, errors.Wrap(ctx, err, op)
}
if cs == nil {
return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("ldapcredential library %q not found", id))
}
return cs, err
}
return nil, errors.New(ctx, errors.InvalidParameter, op, "unrecognized credential library subtype")
}
@@ -464,6 +489,23 @@ func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.Cred
const op = "credentiallibraries.(Service).createInRepo"
var out credential.Library
switch item.GetType() {
case vault.GenericLibrarySubtype.String():
cl, err := toStorageVaultLibrary(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)
}
rl, err := repo.CreateCredentialLibrary(ctx, scopeId, cl)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create credential library"))
}
if rl == nil {
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to create credential library but no error returned from repository.")
}
out = rl
case vault.SSHCertificateLibrarySubtype.String():
cl, err := toStorageVaultSSHCertificateLibrary(ctx, item.GetCredentialStoreId(), item)
if err != nil {
@@ -481,8 +523,8 @@ func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.Cred
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to create ssh certificate credential library but no error returned from repository.")
}
out = rl
default:
cl, err := toStorageVaultLibrary(ctx, item.GetCredentialStoreId(), item)
case vault.LdapCredentialLibrarySubtype.String():
cl, err := toStorageVaultLdapLibrary(ctx, item.GetCredentialStoreId(), item)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
@@ -490,14 +532,16 @@ func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.Cred
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
rl, err := repo.CreateCredentialLibrary(ctx, scopeId, cl)
rl, err := repo.CreateLdapCredentialLibrary(ctx, scopeId, cl)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create credential library"))
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create ldap credential library"))
}
if rl == nil {
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to create credential library but no error returned from repository.")
return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to create ldap credential library but no error returned from repository.")
}
out = rl
default:
return nil, handlers.ApiErrorWithCodeAndMessage(codes.InvalidArgument, "Unknown vault credential library subtype %q", item.GetType())
}
return out, nil
}
@@ -534,6 +578,23 @@ func (s Service) updateInRepo(
return nil, errors.Wrap(ctx, err, op)
}
switch globals.ResourceInfoFromPrefix(id).Subtype {
case vault.GenericLibrarySubtype:
dbMasks = append(dbMasks, maskManager.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."})
}
cl, err := toStorageVaultLibrary(ctx, item.GetCredentialStoreId(), item)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
cl.PublicId = id
out, rowsUpdated, err = repo.UpdateCredentialLibrary(ctx, projId, cl, item.GetVersion(), dbMasks)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to update credential library"))
}
if rowsUpdated == 0 {
return nil, handlers.NotFoundErrorf("Credential Library %q doesn't exist or incorrect version provided.", id)
}
case vault.SSHCertificateLibrarySubtype:
dbMasks = append(dbMasks, sshCertMaskManager.Translate(masks)...)
if getMapUpdate(criticalOptionsField, masks) {
@@ -557,23 +618,25 @@ func (s Service) updateInRepo(
if rowsUpdated == 0 {
return nil, handlers.NotFoundErrorf("Credential Library %q doesn't exist or incorrect version provided.", id)
}
default:
dbMasks = append(dbMasks, maskManager.Translate(masks)...)
case vault.LdapCredentialLibrarySubtype:
dbMasks = append(dbMasks, ldapMaskManager.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."})
}
cl, err := toStorageVaultLibrary(ctx, item.GetCredentialStoreId(), item)
cl, err := toStorageVaultLdapLibrary(ctx, item.GetCredentialStoreId(), item)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
cl.PublicId = id
out, rowsUpdated, err = repo.UpdateCredentialLibrary(ctx, projId, cl, item.GetVersion(), dbMasks)
out, rowsUpdated, err = repo.UpdateLdapCredentialLibrary(ctx, projId, cl, item.GetVersion(), dbMasks)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to update credential library"))
}
if rowsUpdated == 0 {
return nil, handlers.NotFoundErrorf("Credential Library %q doesn't exist or incorrect version provided.", id)
}
default:
return nil, handlers.ApiErrorWithCodeAndMessage(codes.InvalidArgument, "Unknown vault credential library subtype %q", globals.ResourceInfoFromPrefix(id).Subtype)
}
return out, nil
}
@@ -586,10 +649,14 @@ func (s Service) deleteFromRepo(ctx context.Context, scopeId, id string) (bool,
}
rows := 0
switch globals.ResourceInfoFromPrefix(id).Subtype {
case vault.GenericLibrarySubtype:
rows, err = repo.DeleteCredentialLibrary(ctx, scopeId, id)
case vault.SSHCertificateLibrarySubtype:
rows, err = repo.DeleteSSHCertificateCredentialLibrary(ctx, scopeId, id)
case vault.LdapCredentialLibrarySubtype:
rows, err = repo.DeleteLdapCredentialLibrary(ctx, scopeId, id)
default:
rows, err = repo.DeleteCredentialLibrary(ctx, scopeId, id)
return false, handlers.ApiErrorWithCodeAndMessage(codes.InvalidArgument, "Unknown vault credential library subtype %q", globals.ResourceInfoFromPrefix(id).Subtype)
}
if err != nil {
if errors.IsNotFoundError(err) {
@@ -640,6 +707,17 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type, isRec
return res
}
parentId = cl.GetStoreId()
case vault.LdapCredentialLibrarySubtype:
cl, err := repo.LookupLdapCredentialLibrary(ctx, id)
if err != nil {
res.Error = err
return res
}
if cl == nil {
res.Error = handlers.NotFoundError()
return res
}
parentId = cl.GetStoreId()
default:
res.Error = errors.New(ctx, errors.InvalidParameter, op, "unrecognized credential library subtype from id")
return res
@@ -854,7 +932,21 @@ func toProto(ctx context.Context, in credential.Library, opt ...handlers.Option)
VaultSshCertificateCredentialLibraryAttributes: attrs,
}
}
case vault.LdapCredentialLibrarySubtype:
vaultIn, ok := in.(*vault.LdapCredentialLibrary)
if !ok {
return nil, errors.New(ctx, errors.Internal, op, "unable to cast to vault ldap credential library")
}
if outputFields.Has(globals.CredentialTypeField) {
out.CredentialType = vaultIn.GetCredentialType()
}
if outputFields.Has(globals.AttributesField) {
out.Attrs = &pb.CredentialLibrary_VaultLdapCredentialLibraryAttributes{
VaultLdapCredentialLibraryAttributes: &pb.VaultLdapCredentialLibraryAttributes{
Path: wrapperspb.String(vaultIn.GetVaultPath()),
},
}
}
}
return &out, nil
}
@@ -992,20 +1084,33 @@ func toStorageVaultSSHCertificateLibrary(ctx context.Context, storeId string, in
return cs, err
}
func toStorageVaultLdapLibrary(ctx context.Context, storeId string, in *pb.CredentialLibrary) (*vault.LdapCredentialLibrary, error) {
const op = "credentiallibraries.toStorageVaultLdapLibrary"
var opts []vault.Option
if in.GetName() != nil {
opts = append(opts, vault.WithName(in.GetName().GetValue()))
}
if in.GetDescription() != nil {
opts = append(opts, vault.WithDescription(in.GetDescription().GetValue()))
}
attrs := in.GetVaultLdapCredentialLibraryAttributes()
cs, err := vault.NewLdapCredentialLibrary(storeId, attrs.GetPath().GetValue(), opts...)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to build credential library"))
}
return cs, nil
}
// A validateX method should exist for each method above. These methods do not make calls to any backing service but enforce
// requirements on the structure of the request. They verify that:
// - The path passed in is correctly formatted
// - All required parameters are set
// - There are no conflicting parameters provided
func validateGetRequest(req *pbs.GetCredentialLibraryRequest) error {
prefix := ""
switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype {
case vault.SSHCertificateLibrarySubtype:
prefix = globals.VaultSshCertificateCredentialLibraryPrefix
default:
prefix = globals.VaultCredentialLibraryPrefix
}
return handlers.ValidateGetRequest(handlers.NoopValidatorFn, req, prefix)
return handlers.ValidateGetRequest(handlers.NoopValidatorFn, req, globals.VaultCredentialLibraryPrefix, globals.VaultSshCertificateCredentialLibraryPrefix, globals.VaultLdapCredentialLibraryPrefix)
}
func validateCreateRequest(req *pbs.CreateCredentialLibraryRequest) error {
@@ -1048,8 +1153,9 @@ func validateCreateRequest(req *pbs.CreateCredentialLibraryRequest) error {
}
if t != vault.GenericLibrarySubtype.String() &&
t != vault.SSHCertificateLibrarySubtype.String() {
badFields[globals.CredentialStoreIdField] = fmt.Sprintf("Type must be a vault subtype %q or %q", vault.GenericLibrarySubtype.String(), vault.SSHCertificateLibrarySubtype.String())
t != vault.SSHCertificateLibrarySubtype.String() &&
t != vault.LdapCredentialLibrarySubtype.String() {
badFields[globals.CredentialStoreIdField] = fmt.Sprintf("Type must be a vault subtype %q, %q or %q", vault.GenericLibrarySubtype.String(), vault.SSHCertificateLibrarySubtype.String(), vault.LdapCredentialLibrarySubtype.String())
}
switch req.GetItem().GetType() {
@@ -1111,6 +1217,17 @@ func validateCreateRequest(req *pbs.CreateCredentialLibraryRequest) error {
badFields[keyTypeField] = "If set, value must be 'ed25519', 'ecdsa', or 'rsa'."
}
validateKeyBits(badFields, attrs.GetKeyBits().GetValue(), attrs.GetKeyType().GetValue())
case vault.LdapCredentialLibrarySubtype.String():
if req.GetItem().GetCredentialType() != "" {
badFields[globals.CredentialTypeField] = "This field is read only and cannot be set."
}
attrs := req.GetItem().GetVaultLdapCredentialLibraryAttributes()
if attrs == nil {
badFields[attributesPathField] = "This is a required field."
}
if attrs.GetPath().GetValue() == "" {
badFields[vaultPathField] = "This is a required field."
}
}
default:
badFields[globals.CredentialStoreIdField] = "This field must be a valid credential store id."
@@ -1120,17 +1237,9 @@ func validateCreateRequest(req *pbs.CreateCredentialLibraryRequest) error {
}
func validateUpdateRequest(req *pbs.UpdateCredentialLibraryRequest, currentCredentialType globals.CredentialType) error {
prefix := ""
st := globals.ResourceInfoFromPrefix(req.GetId()).Subtype
switch st {
case vault.GenericLibrarySubtype:
prefix = globals.VaultCredentialLibraryPrefix
case vault.SSHCertificateLibrarySubtype:
prefix = globals.VaultSshCertificateCredentialLibraryPrefix
}
return handlers.ValidateUpdateRequest(req, req.GetItem(), func() map[string]string {
badFields := map[string]string{}
switch st {
switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype {
case vault.GenericLibrarySubtype:
if req.GetItem().GetType() != "" && req.GetItem().GetType() != vault.GenericLibrarySubtype.String() {
badFields[globals.TypeField] = "Cannot modify resource type."
@@ -1175,13 +1284,27 @@ func validateUpdateRequest(req *pbs.UpdateCredentialLibraryRequest, currentCrede
}
validateKeyBits(badFields, attrs.GetKeyBits().GetValue(), attrs.GetKeyType().GetValue())
}
case vault.LdapCredentialLibrarySubtype:
if req.GetItem().GetType() != "" && req.GetItem().GetType() != vault.LdapCredentialLibrarySubtype.String() {
badFields[globals.TypeField] = "Cannot modify resource type."
}
if req.GetItem().GetCredentialType() != "" && req.GetItem().GetCredentialType() != string(currentCredentialType) {
badFields[globals.CredentialTypeField] = "Cannot modify credential type."
}
attrs := req.GetItem().GetVaultLdapCredentialLibraryAttributes()
if attrs != nil {
if handlers.MaskContains(req.GetUpdateMask().GetPaths(), vaultPathField) && attrs.GetPath().GetValue() == "" {
badFields[vaultPathField] = "This is a required field and cannot be set to empty."
}
}
}
return badFields
}, prefix)
}, globals.VaultCredentialLibraryPrefix, globals.VaultSshCertificateCredentialLibraryPrefix, globals.VaultLdapCredentialLibraryPrefix)
}
func validateDeleteRequest(req *pbs.DeleteCredentialLibraryRequest) error {
return handlers.ValidateDeleteRequest(handlers.NoopValidatorFn, req, globals.VaultCredentialLibraryPrefix, globals.VaultSshCertificateCredentialLibraryPrefix)
return handlers.ValidateDeleteRequest(handlers.NoopValidatorFn, req, globals.VaultCredentialLibraryPrefix, globals.VaultSshCertificateCredentialLibraryPrefix, globals.VaultLdapCredentialLibraryPrefix)
}
func validateListRequest(ctx context.Context, req *pbs.ListCredentialLibrariesRequest) error {
@@ -14,6 +14,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/authtoken"
@@ -86,6 +87,25 @@ func sshCredentialLibraryToProto(credLib *vault.SSHCertificateCredentialLibrary,
}
}
func ldapCredentialLibraryToProto(credLib *vault.LdapCredentialLibrary, project *iam.Scope) *pb.CredentialLibrary {
return &pb.CredentialLibrary{
Id: credLib.GetPublicId(),
CredentialStoreId: credLib.GetStoreId(),
CredentialType: credLib.GetCredentialType(),
Scope: &scopepb.ScopeInfo{Id: project.GetPublicId(), Type: scope.Project.String(), ParentScopeId: project.GetParentId()},
CreatedTime: credLib.GetCreateTime().GetTimestamp(),
UpdatedTime: credLib.GetUpdateTime().GetTimestamp(),
Version: credLib.GetVersion(),
Type: vault.LdapCredentialLibrarySubtype.String(),
AuthorizedActions: testAuthorizedActions,
Attrs: &pb.CredentialLibrary_VaultLdapCredentialLibraryAttributes{
VaultLdapCredentialLibraryAttributes: &pb.VaultLdapCredentialLibraryAttributes{
Path: wrapperspb.String(credLib.GetVaultPath()),
},
},
}
}
func TestList(t *testing.T) {
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
@@ -114,6 +134,9 @@ func TestList(t *testing.T) {
for _, l := range vault.TestSSHCertificateCredentialLibraries(t, conn, wrapper, store.GetPublicId(), 10) {
wantLibraries = append(wantLibraries, sshCredentialLibraryToProto(l, prj))
}
for _, l := range vault.TestLdapCredentialLibraries(t, conn, wrapper, store.GetPublicId(), 10) {
wantLibraries = append(wantLibraries, ldapCredentialLibraryToProto(l, prj))
}
cases := []struct {
name string
@@ -131,7 +154,7 @@ func TestList(t *testing.T) {
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 20,
EstItemCount: 30,
},
anonRes: &pbs.ListCredentialLibrariesResponse{
Items: wantLibraries,
@@ -139,7 +162,7 @@ func TestList(t *testing.T) {
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 20,
EstItemCount: 30,
},
},
{
@@ -264,16 +287,20 @@ func TestList_Attributes(t *testing.T) {
_, prj := iam.TestScopes(t, iamRepo)
ts := vault.TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 2)
storeGeneric, storeSSHCertificate := ts[0], ts[1]
ts := vault.TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 3)
storeGeneric, storeSSHCertificate, storeLdap := ts[0], ts[1], ts[2]
var wantLibrariesGeneric []*pb.CredentialLibrary
var wantLibrariesSSHCertificate []*pb.CredentialLibrary
var wantLibrariesLdap []*pb.CredentialLibrary
for _, l := range vault.TestCredentialLibraries(t, conn, wrapper, storeGeneric.GetPublicId(), globals.UnspecifiedCredentialType, 5) {
wantLibrariesGeneric = append(wantLibrariesGeneric, vaultCredentialLibraryToProto(l, prj))
}
for _, l := range vault.TestSSHCertificateCredentialLibraries(t, conn, wrapper, storeSSHCertificate.GetPublicId(), 10) {
wantLibrariesSSHCertificate = append(wantLibrariesSSHCertificate, sshCredentialLibraryToProto(l, prj))
}
for _, l := range vault.TestLdapCredentialLibraries(t, conn, wrapper, storeLdap.GetPublicId(), 10) {
wantLibrariesLdap = append(wantLibrariesLdap, ldapCredentialLibraryToProto(l, prj))
}
cases := []struct {
name string
@@ -318,6 +345,24 @@ func TestList_Attributes(t *testing.T) {
RemovedIds: nil,
}, // anonymous user does not have access to attributes
},
{
name: "Filter on Attribute Ldap Library",
req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: storeLdap.GetPublicId(), Filter: fmt.Sprintf(`"/item/attributes/path"==%q`, wantLibrariesLdap[2].GetVaultLdapCredentialLibraryAttributes().GetPath().Value)},
res: &pbs.ListCredentialLibrariesResponse{
Items: wantLibrariesLdap[2:3],
ResponseType: "complete",
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 1,
},
anonRes: &pbs.ListCredentialLibrariesResponse{
ResponseType: "complete",
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
}, // anonymous user does not have access to attributes
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
@@ -586,6 +631,51 @@ func TestCreate(t *testing.T) {
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "No Vault LDAP path",
req: &pbs.CreateCredentialLibraryRequest{
Item: &pb.CredentialLibrary{
CredentialStoreId: store.GetPublicId(),
Type: vault.LdapCredentialLibrarySubtype.String(),
Attrs: &pb.CredentialLibrary_VaultLdapCredentialLibraryAttributes{
VaultLdapCredentialLibraryAttributes: &pb.VaultLdapCredentialLibraryAttributes{
Path: wrapperspb.String(""),
},
},
},
},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Invalid Vault LDAP credential type",
req: &pbs.CreateCredentialLibraryRequest{
Item: &pb.CredentialLibrary{
CredentialStoreId: store.GetPublicId(),
Type: vault.LdapCredentialLibrarySubtype.String(),
CredentialType: string(globals.SshPrivateKeyCredentialType),
Attrs: &pb.CredentialLibrary_VaultLdapCredentialLibraryAttributes{
VaultLdapCredentialLibraryAttributes: &pb.VaultLdapCredentialLibraryAttributes{
Path: wrapperspb.String("ldap/invalid/path"),
},
},
},
},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Invalid credential library type",
req: &pbs.CreateCredentialLibraryRequest{
Item: &pb.CredentialLibrary{
CredentialStoreId: store.GetPublicId(),
Type: "bla-invalid",
CredentialType: "bla-invalid",
},
},
res: nil,
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
},
{
name: "Using POST method",
req: &pbs.CreateCredentialLibraryRequest{Item: &pb.CredentialLibrary{
@@ -1103,6 +1193,40 @@ func TestCreate(t *testing.T) {
},
},
},
{
name: "Create a valid Vault LDAP Credential library",
req: &pbs.CreateCredentialLibraryRequest{
Item: &pb.CredentialLibrary{
CredentialStoreId: store.GetPublicId(),
Type: vault.LdapCredentialLibrarySubtype.String(),
Attrs: &pb.CredentialLibrary_VaultLdapCredentialLibraryAttributes{
VaultLdapCredentialLibraryAttributes: &pb.VaultLdapCredentialLibraryAttributes{
Path: wrapperspb.String("ldap/creds/hi"),
},
},
},
},
idPrefix: globals.VaultLdapCredentialLibraryPrefix + "_",
res: &pbs.CreateCredentialLibraryResponse{
Uri: fmt.Sprintf("credential-libraries/%s_", globals.VaultLdapCredentialLibraryPrefix),
Item: &pb.CredentialLibrary{
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: vault.LdapCredentialLibrarySubtype.String(),
CredentialType: string(globals.UsernamePasswordDomainCredentialType),
Attrs: &pb.CredentialLibrary_VaultLdapCredentialLibraryAttributes{
VaultLdapCredentialLibraryAttributes: &pb.VaultLdapCredentialLibraryAttributes{
Path: wrapperspb.String("ldap/creds/hi"),
},
},
AuthorizedActions: testAuthorizedActions,
},
},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
@@ -1217,6 +1341,13 @@ func TestGet(t *testing.T) {
sshCertLib, err := repo.CreateSSHCertificateCredentialLibrary(context.Background(), prj.GetPublicId(), lib2)
require.NoError(t, err)
libLdap1, err := vault.NewLdapCredentialLibrary(store.GetPublicId(), "ldap/creds/test")
require.NoError(t, err)
require.NotNil(t, libLdap1)
libLdap1, err = repo.CreateLdapCredentialLibrary(t.Context(), prj.GetPublicId(), libLdap1)
require.NoError(t, err)
require.NotNil(t, libLdap1)
cases := []struct {
name string
id string
@@ -1367,6 +1498,28 @@ func TestGet(t *testing.T) {
},
},
},
{
name: "success-ldap",
id: libLdap1.GetPublicId(),
res: &pbs.GetCredentialLibraryResponse{
Item: &pb.CredentialLibrary{
Id: libLdap1.GetPublicId(),
CredentialStoreId: libLdap1.GetStoreId(),
CredentialType: libLdap1.GetCredentialType(),
Scope: &scopepb.ScopeInfo{Id: store.GetProjectId(), Type: scope.Project.String(), ParentScopeId: prj.GetParentId()},
Type: vault.LdapCredentialLibrarySubtype.String(),
AuthorizedActions: testAuthorizedActions,
CreatedTime: libLdap1.CreateTime.GetTimestamp(),
UpdatedTime: libLdap1.UpdateTime.GetTimestamp(),
Version: 1,
Attrs: &pb.CredentialLibrary_VaultLdapCredentialLibraryAttributes{
VaultLdapCredentialLibraryAttributes: &pb.VaultLdapCredentialLibraryAttributes{
Path: wrapperspb.String(libLdap1.GetVaultPath()),
},
},
},
},
},
{
name: "not found error",
id: fmt.Sprintf("%s_1234567890", globals.VaultCredentialLibraryPrefix),
@@ -1429,6 +1582,7 @@ func TestDelete(t *testing.T) {
store := vault.TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0]
vl := vault.TestCredentialLibraries(t, conn, wrapper, store.GetPublicId(), globals.UnspecifiedCredentialType, 1)[0]
vl2 := vault.TestSSHCertificateCredentialLibraries(t, conn, wrapper, store.GetPublicId(), 1)[0]
vl3 := vault.TestLdapCredentialLibraries(t, conn, wrapper, store.GetPublicId(), 1)[0]
s, err := NewService(ctx, iamRepoFn, repoFn, 1000)
require.NoError(t, err)
cases := []struct {
@@ -1445,6 +1599,10 @@ func TestDelete(t *testing.T) {
name: "success-ssh-cert",
id: vl2.GetPublicId(),
},
{
name: "success-ldap",
id: vl3.GetPublicId(),
},
{
name: "not found error",
id: fmt.Sprintf("%s_1234567890", globals.VaultCredentialLibraryPrefix),
@@ -3244,6 +3402,287 @@ func TestUpdate_SSHCertificateCredentialLibrary(t *testing.T) {
}
}
func TestUpdate_LdapCredentialLibrary(t *testing.T) {
testCtx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
kms := kms.TestKms(t, conn, wrapper)
sche := scheduler.TestScheduler(t, conn, wrapper)
rw := db.New(conn)
iamRepo := iam.TestRepo(t, conn, wrapper)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
repoFn := func() (*vault.Repository, error) {
return vault.NewRepository(testCtx, rw, rw, kms, sche)
}
_, prj := iam.TestScopes(t, iamRepo)
ctx := auth.DisabledAuthTestContext(iamRepoFn, prj.GetPublicId())
s, err := NewService(testCtx, iamRepoFn, repoFn, 1000)
require.NoError(t, err)
cs := vault.TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)
store := cs[0]
freshLibrary := func(opt ...vault.Option) (*vault.LdapCredentialLibrary, func()) {
repo, err := repoFn()
require.NoError(t, err)
lib, err := vault.NewLdapCredentialLibrary(store.GetPublicId(), "ldap/creds/foo", opt...)
require.NoError(t, err)
vl, err := repo.CreateLdapCredentialLibrary(ctx, prj.GetPublicId(), lib)
require.NoError(t, err)
clean := func() {
_, err := s.DeleteCredentialLibrary(ctx, &pbs.DeleteCredentialLibraryRequest{Id: vl.GetPublicId()})
require.NoError(t, err)
}
return vl, clean
}
tests := []struct {
name string
req *pbs.UpdateCredentialLibraryRequest
res func(*pb.CredentialLibrary) *pb.CredentialLibrary
wantErr bool
wantErrStatus int
wantErrStr string
}{
{
name: "updateNonExistentField",
req: &pbs.UpdateCredentialLibraryRequest{
Id: "", // Set at test runtime.
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"doesntExist"}},
Item: &pb.CredentialLibrary{
Name: wrapperspb.String("updateNonExistentField_test"),
},
},
wantErr: true,
wantErrStatus: runtime.HTTPStatusFromCode(codes.InvalidArgument),
wantErrStr: "No valid fields included in the update mask.",
},
{
name: "updateImmutableField",
req: &pbs.UpdateCredentialLibraryRequest{
Id: "", // Set at test runtime.
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"storeId"}},
Item: &pb.CredentialLibrary{
CredentialStoreId: "immutable",
},
},
wantErr: true,
wantErrStatus: runtime.HTTPStatusFromCode(codes.InvalidArgument),
wantErrStr: "No valid fields included in the update mask.",
},
{
name: "updateValidFieldWithInvalidData",
req: &pbs.UpdateCredentialLibraryRequest{
Id: "", // Set at test runtime.
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"attributes.path"}},
Item: &pb.CredentialLibrary{
Attrs: &pb.CredentialLibrary_VaultLdapCredentialLibraryAttributes{
VaultLdapCredentialLibraryAttributes: &pb.VaultLdapCredentialLibraryAttributes{
Path: wrapperspb.String("invalid_path"),
},
},
},
},
wantErr: true,
wantErrStr: "vault_path_must_have_staticcred_or_creds constraint failed",
},
{
name: "updateImmutableCredentialTypeField",
req: &pbs.UpdateCredentialLibraryRequest{
Id: "", // Set at test runtime.
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"credentialType"}},
Item: &pb.CredentialLibrary{
CredentialType: string(globals.SshPrivateKeyCredentialType),
},
},
wantErr: true,
wantErrStatus: runtime.HTTPStatusFromCode(codes.InvalidArgument),
wantErrStr: "Cannot modify credential type.",
},
{
name: "updateImmutableTypeField",
req: &pbs.UpdateCredentialLibraryRequest{
Id: "", // Set at test runtime.
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"type"}},
Item: &pb.CredentialLibrary{
Type: string(globals.SshCertificateCredentialType),
},
},
wantErr: true,
wantErrStatus: runtime.HTTPStatusFromCode(codes.InvalidArgument),
wantErrStr: "Cannot modify resource type.",
},
{
name: "unsetVaultPath",
req: &pbs.UpdateCredentialLibraryRequest{
Id: "", // Set at test runtime.
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"attributes.path"}},
Item: &pb.CredentialLibrary{
Attrs: &pb.CredentialLibrary_VaultLdapCredentialLibraryAttributes{
VaultLdapCredentialLibraryAttributes: &pb.VaultLdapCredentialLibraryAttributes{
Path: wrapperspb.String(""),
},
},
},
},
wantErr: true,
wantErrStatus: runtime.HTTPStatusFromCode(codes.InvalidArgument),
wantErrStr: "attributes.path\", desc: \"This is a required field and cannot be set to empty.",
},
{
name: "updateName",
req: &pbs.UpdateCredentialLibraryRequest{
Id: "", // Set at test runtime
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"name"}},
Item: &pb.CredentialLibrary{
Name: wrapperspb.String("updated_name"),
},
},
res: func(cl *pb.CredentialLibrary) *pb.CredentialLibrary {
cl.Name = wrapperspb.String("updated_name")
return cl
},
},
{
name: "updateDescription",
req: &pbs.UpdateCredentialLibraryRequest{
Id: "", // Set at test runtime
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"description"}},
Item: &pb.CredentialLibrary{
Description: wrapperspb.String("updated_description"),
},
},
res: func(cl *pb.CredentialLibrary) *pb.CredentialLibrary {
cl.Description = wrapperspb.String("updated_description")
return cl
},
},
{
name: "updateValidVaultPath",
req: &pbs.UpdateCredentialLibraryRequest{
Id: "", // Set at test runtime
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"attributes.path"}},
Item: &pb.CredentialLibrary{
Attrs: &pb.CredentialLibrary_VaultLdapCredentialLibraryAttributes{
VaultLdapCredentialLibraryAttributes: &pb.VaultLdapCredentialLibraryAttributes{
Path: wrapperspb.String("ldap/static-cred/updated/path"),
},
},
},
},
res: func(cl *pb.CredentialLibrary) *pb.CredentialLibrary {
cl.GetVaultLdapCredentialLibraryAttributes().Path = wrapperspb.String("ldap/static-cred/updated/path")
return cl
},
},
{
name: "updateMultipleOneNonExistent",
req: &pbs.UpdateCredentialLibraryRequest{
Id: "", // Set at test runtime.
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"name", "doesntExist"}},
Item: &pb.CredentialLibrary{
Name: wrapperspb.String("updated_name"),
},
},
res: func(cl *pb.CredentialLibrary) *pb.CredentialLibrary {
cl.Name = wrapperspb.String("updated_name")
return cl
},
},
{
name: "updateMultipleOneImmutable",
req: &pbs.UpdateCredentialLibraryRequest{
Id: "", // Set at test runtime.
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"name", "credentialStoreId"}},
Item: &pb.CredentialLibrary{
Name: wrapperspb.String("updated_name"),
CredentialStoreId: "immutable",
},
},
res: func(cl *pb.CredentialLibrary) *pb.CredentialLibrary {
cl.Name = wrapperspb.String("updated_name")
return cl
},
},
{
name: "updateMultiple",
req: &pbs.UpdateCredentialLibraryRequest{
Id: "", // Set at test runtime
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"name", "attributes.path"}},
Item: &pb.CredentialLibrary{
Name: wrapperspb.String("updated_name"),
Attrs: &pb.CredentialLibrary_VaultLdapCredentialLibraryAttributes{
VaultLdapCredentialLibraryAttributes: &pb.VaultLdapCredentialLibraryAttributes{
Path: wrapperspb.String("ldap/creds/updated/path"),
},
},
},
},
res: func(cl *pb.CredentialLibrary) *pb.CredentialLibrary {
cl.Name = wrapperspb.String("updated_name")
cl.GetVaultLdapCredentialLibraryAttributes().Path = wrapperspb.String("ldap/creds/updated/path")
return cl
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
st, cleanup := freshLibrary()
defer cleanup()
if tc.req.Item.GetVersion() == 0 {
tc.req.Item.Version = 1
}
if tc.req.GetId() == "" {
tc.req.Id = st.GetPublicId()
}
resToChange, err := s.GetCredentialLibrary(ctx, &pbs.GetCredentialLibraryRequest{Id: st.GetPublicId()})
require.NoError(err)
got, gErr := s.UpdateCredentialLibrary(ctx, tc.req)
if tc.wantErr {
require.ErrorContains(gErr, tc.wantErrStr)
gApiErr, ok := gErr.(*handlers.ApiError)
if ok {
// We don't always return status.
require.NotNil(gApiErr)
require.EqualValues(tc.wantErrStatus, gApiErr.Status)
}
require.Nil(got)
return
}
require.NoError(gErr)
require.NotNil(got)
want := &pbs.UpdateCredentialLibraryResponse{Item: tc.res(resToChange.GetItem())}
gotUpdateTime := got.GetItem().GetUpdatedTime()
created := st.GetCreateTime().GetTimestamp()
assert.True(gotUpdateTime.AsTime().After(created.AsTime()), "Should have been updated after it's creation. Was updated %v, which is after %v", gotUpdateTime, created)
want.Item.UpdatedTime = got.Item.UpdatedTime
assert.EqualValues(2, got.Item.Version)
want.Item.Version = 2
assert.Empty(cmp.Diff(
got,
want,
protocmp.Transform(),
cmpopts.SortSlices(func(a, b string) bool {
return a < b
}),
))
})
}
}
func TestListPagination(t *testing.T) {
// Set database read timeout to avoid duplicates in response
oldReadTimeout := globals.RefreshReadLookbackDuration
@@ -3292,6 +3731,9 @@ func TestListPagination(t *testing.T) {
for _, l := range vault.TestSSHCertificateCredentialLibraries(t, conn, wrapper, credStore.GetPublicId(), 5) {
allCredentialLibraries = append(allCredentialLibraries, sshCredentialLibraryToProto(l, prj))
}
for _, l := range vault.TestLdapCredentialLibraries(t, conn, wrapper, credStore.GetPublicId(), 5) {
allCredentialLibraries = append(allCredentialLibraries, ldapCredentialLibraryToProto(l, prj))
}
// Reverse as we return items sorted by create_time desceding (newest first)
slices.Reverse(allCredentialLibraries)
@@ -3345,7 +3787,7 @@ func TestListPagination(t *testing.T) {
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 10,
EstItemCount: 15,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -3370,7 +3812,7 @@ func TestListPagination(t *testing.T) {
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 10,
EstItemCount: 15,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -3382,10 +3824,10 @@ func TestListPagination(t *testing.T) {
// Request rest of results
req.ListToken = got.ListToken
req.PageSize = 10
req.PageSize = 15
got, err = s.ListCredentialLibraries(ctx, req)
require.NoError(err)
require.Len(got.GetItems(), 6)
require.Len(got.GetItems(), 11)
// Compare without comparing the list token
assert.Empty(
cmp.Diff(
@@ -3396,7 +3838,7 @@ func TestListPagination(t *testing.T) {
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 10,
EstItemCount: 15,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -3421,14 +3863,14 @@ func TestListPagination(t *testing.T) {
// Update one of the other stores
allCredentialLibraries[1].Name = wrapperspb.String("new-name")
allCredentialLibraries[1].Version = 2
updatedLibrary := &vault.SSHCertificateCredentialLibrary{
SSHCertificateCredentialLibrary: &store.SSHCertificateCredentialLibrary{
updatedLibrary := &vault.LdapCredentialLibrary{
LdapCredentialLibrary: &store.LdapCredentialLibrary{
PublicId: allCredentialLibraries[1].GetId(),
StoreId: allCredentialLibraries[1].GetCredentialStoreId(),
Name: allCredentialLibraries[1].Name.Value,
},
}
cred, _, err := vaultRepo.UpdateSSHCertificateCredentialLibrary(ctx, prj.PublicId, updatedLibrary, 1, []string{"name"})
cred, _, err := vaultRepo.UpdateLdapCredentialLibrary(ctx, prj.PublicId, updatedLibrary, 1, []string{"name"})
require.NoError(err)
allCredentialLibraries[1].UpdatedTime = cred.UpdateTime.GetTimestamp()
allCredentialLibraries[1].Version = cred.Version
@@ -3462,7 +3904,7 @@ func TestListPagination(t *testing.T) {
SortDir: "desc",
// Should contain the deleted library
RemovedIds: []string{deletedCredLib.Id},
EstItemCount: 10,
EstItemCount: 15,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -3487,7 +3929,7 @@ func TestListPagination(t *testing.T) {
SortBy: "updated_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 10,
EstItemCount: 15,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -3515,7 +3957,7 @@ func TestListPagination(t *testing.T) {
SortDir: "desc",
// Should be empty again
RemovedIds: nil,
EstItemCount: 10,
EstItemCount: 15,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -3538,7 +3980,7 @@ func TestListPagination(t *testing.T) {
SortBy: "created_time",
SortDir: "desc",
RemovedIds: nil,
EstItemCount: 10,
EstItemCount: 15,
},
cmpopts.SortSlices(func(a, b string) bool {
return a < b
@@ -2056,6 +2056,7 @@ func validateAddCredentialSourcesRequest(req *pbs.AddTargetCredentialSourcesRequ
for _, cl := range req.GetBrokeredCredentialSourceIds() {
if !handlers.ValidId(handlers.Id(cl),
globals.VaultCredentialLibraryPrefix,
globals.VaultLdapCredentialLibraryPrefix,
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
@@ -2069,6 +2070,7 @@ func validateAddCredentialSourcesRequest(req *pbs.AddTargetCredentialSourcesRequ
if !handlers.ValidId(handlers.Id(cl),
globals.VaultCredentialLibraryPrefix,
globals.VaultSshCertificateCredentialLibraryPrefix,
globals.VaultLdapCredentialLibraryPrefix,
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
@@ -2094,6 +2096,7 @@ func validateSetCredentialSourcesRequest(req *pbs.SetTargetCredentialSourcesRequ
for _, cl := range req.GetBrokeredCredentialSourceIds() {
if !handlers.ValidId(handlers.Id(cl),
globals.VaultCredentialLibraryPrefix,
globals.VaultLdapCredentialLibraryPrefix,
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
@@ -2107,6 +2110,7 @@ func validateSetCredentialSourcesRequest(req *pbs.SetTargetCredentialSourcesRequ
if !handlers.ValidId(handlers.Id(cl),
globals.VaultCredentialLibraryPrefix,
globals.VaultSshCertificateCredentialLibraryPrefix,
globals.VaultLdapCredentialLibraryPrefix,
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
@@ -2136,6 +2140,7 @@ func validateRemoveCredentialSourcesRequest(req *pbs.RemoveTargetCredentialSourc
for _, cl := range req.GetBrokeredCredentialSourceIds() {
if !handlers.ValidId(handlers.Id(cl),
globals.VaultCredentialLibraryPrefix,
globals.VaultLdapCredentialLibraryPrefix,
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
@@ -2149,6 +2154,7 @@ func validateRemoveCredentialSourcesRequest(req *pbs.RemoveTargetCredentialSourc
if !handlers.ValidId(handlers.Id(cl),
globals.VaultCredentialLibraryPrefix,
globals.VaultSshCertificateCredentialLibraryPrefix,
globals.VaultLdapCredentialLibraryPrefix,
globals.UsernamePasswordCredentialPrefix,
globals.UsernamePasswordCredentialPreviousPrefix,
globals.UsernamePasswordDomainCredentialPrefix,
@@ -77,6 +77,11 @@ message CredentialLibrary {
(custom_options.v1.generate_sdk_option) = true,
(custom_options.v1.subtype) = "vault-generic"
];
VaultLdapCredentialLibraryAttributes vault_ldap_credential_library_attributes = 104 [
(google.api.field_visibility).restriction = "INTERNAL",
(custom_options.v1.generate_sdk_option) = true,
(custom_options.v1.subtype) = "vault-ldap"
];
}
// Output only. The available actions on this resource for this user.
@@ -210,3 +215,15 @@ message VaultSSHCertificateCredentialLibraryAttributes {
}
]; // @gotags: `class:"public"`
}
// The attributes of a vault LDAP Credential Library.
message VaultLdapCredentialLibraryAttributes {
// The path in Vault to request credentials from.
google.protobuf.StringValue path = 10 [
(custom_options.v1.generate_sdk_option) = true,
(custom_options.v1.mask_mapping) = {
this: "attributes.path"
that: "VaultPath"
}
]; // @gotags: `class:"public"`
}
@@ -58,6 +58,7 @@ type CredentialLibrary struct {
// *CredentialLibrary_VaultCredentialLibraryAttributes
// *CredentialLibrary_VaultSshCertificateCredentialLibraryAttributes
// *CredentialLibrary_VaultGenericCredentialLibraryAttributes
// *CredentialLibrary_VaultLdapCredentialLibraryAttributes
Attrs isCredentialLibrary_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"`
@@ -205,6 +206,15 @@ func (x *CredentialLibrary) GetVaultGenericCredentialLibraryAttributes() *VaultC
return nil
}
func (x *CredentialLibrary) GetVaultLdapCredentialLibraryAttributes() *VaultLdapCredentialLibraryAttributes {
if x != nil {
if x, ok := x.Attrs.(*CredentialLibrary_VaultLdapCredentialLibraryAttributes); ok {
return x.VaultLdapCredentialLibraryAttributes
}
}
return nil
}
func (x *CredentialLibrary) GetAuthorizedActions() []string {
if x != nil {
return x.AuthorizedActions
@@ -247,6 +257,10 @@ type CredentialLibrary_VaultGenericCredentialLibraryAttributes struct {
VaultGenericCredentialLibraryAttributes *VaultCredentialLibraryAttributes `protobuf:"bytes,103,opt,name=vault_generic_credential_library_attributes,json=vaultGenericCredentialLibraryAttributes,proto3,oneof"`
}
type CredentialLibrary_VaultLdapCredentialLibraryAttributes struct {
VaultLdapCredentialLibraryAttributes *VaultLdapCredentialLibraryAttributes `protobuf:"bytes,104,opt,name=vault_ldap_credential_library_attributes,json=vaultLdapCredentialLibraryAttributes,proto3,oneof"`
}
func (*CredentialLibrary_Attributes) isCredentialLibrary_Attrs() {}
func (*CredentialLibrary_VaultCredentialLibraryAttributes) isCredentialLibrary_Attrs() {}
@@ -256,6 +270,8 @@ func (*CredentialLibrary_VaultSshCertificateCredentialLibraryAttributes) isCrede
func (*CredentialLibrary_VaultGenericCredentialLibraryAttributes) isCredentialLibrary_Attrs() {}
func (*CredentialLibrary_VaultLdapCredentialLibraryAttributes) isCredentialLibrary_Attrs() {}
// The attributes of a vault typed Credential Library.
type VaultCredentialLibraryAttributes struct {
state protoimpl.MessageState `protogen:"open.v1"`
@@ -438,11 +454,57 @@ func (x *VaultSSHCertificateCredentialLibraryAttributes) GetAdditionalValidPrinc
return nil
}
// The attributes of a vault LDAP Credential Library.
type VaultLdapCredentialLibraryAttributes struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The path in Vault to request credentials from.
Path *wrapperspb.StringValue `protobuf:"bytes,10,opt,name=path,proto3" json:"path,omitempty" class:"public"` // @gotags: `class:"public"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *VaultLdapCredentialLibraryAttributes) Reset() {
*x = VaultLdapCredentialLibraryAttributes{}
mi := &file_controller_api_resources_credentiallibraries_v1_credential_library_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *VaultLdapCredentialLibraryAttributes) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VaultLdapCredentialLibraryAttributes) ProtoMessage() {}
func (x *VaultLdapCredentialLibraryAttributes) ProtoReflect() protoreflect.Message {
mi := &file_controller_api_resources_credentiallibraries_v1_credential_library_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use VaultLdapCredentialLibraryAttributes.ProtoReflect.Descriptor instead.
func (*VaultLdapCredentialLibraryAttributes) Descriptor() ([]byte, []int) {
return file_controller_api_resources_credentiallibraries_v1_credential_library_proto_rawDescGZIP(), []int{3}
}
func (x *VaultLdapCredentialLibraryAttributes) GetPath() *wrapperspb.StringValue {
if x != nil {
return x.Path
}
return nil
}
var File_controller_api_resources_credentiallibraries_v1_credential_library_proto protoreflect.FileDescriptor
const file_controller_api_resources_credentiallibraries_v1_credential_library_proto_rawDesc = "" +
"\n" +
"Hcontroller/api/resources/credentiallibraries/v1/credential_library.proto\x12/controller.api.resources.credentiallibraries.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\"\xae\v\n" +
"Hcontroller/api/resources/credentiallibraries/v1/credential_library.proto\x12/controller.api.resources.credentiallibraries.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\"\x84\r\n" +
"\x11CredentialLibrary\x12\x0e\n" +
"\x02id\x18\n" +
" \x01(\tR\x02id\x120\n" +
@@ -464,7 +526,10 @@ const file_controller_api_resources_credentiallibraries_v1_credential_library_pr
"3vault_ssh_certificate_credential_library_attributes\x18f \x01(\v2_.controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributesB-\xa0\xda)\x01\x9a\xe3)\x15vault-ssh-certificate\xfa\xd2\xe4\x93\x02\n" +
"\x12\bINTERNALH\x00R.vaultSshCertificateCredentialLibraryAttributes\x12\xd8\x01\n" +
"+vault_generic_credential_library_attributes\x18g \x01(\v2Q.controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributesB%\xa0\xda)\x01\x9a\xe3)\rvault-generic\xfa\xd2\xe4\x93\x02\n" +
"\x12\bINTERNALH\x00R'vaultGenericCredentialLibraryAttributes\x12/\n" +
"\x12\bINTERNALH\x00R'vaultGenericCredentialLibraryAttributes\x12\xd3\x01\n" +
"(vault_ldap_credential_library_attributes\x18h \x01(\v2U.controller.api.resources.credentiallibraries.v1.VaultLdapCredentialLibraryAttributesB\"\xa0\xda)\x01\x9a\xe3)\n" +
"vault-ldap\xfa\xd2\xe4\x93\x02\n" +
"\x12\bINTERNALH\x00R$vaultLdapCredentialLibraryAttributes\x12/\n" +
"\x12authorized_actions\x18\xac\x02 \x03(\tR\x12authorized_actions\x12/\n" +
"\x0fcredential_type\x18\xb6\x02 \x01(\tB\x04\xa0\xda)\x01R\x0fcredential_type\x12b\n" +
"\x1ccredential_mapping_overrides\x18\xc0\x02 \x01(\v2\x17.google.protobuf.StructB\x04\xa0\xda)\x01R\x1ccredential_mapping_overridesB\a\n" +
@@ -507,7 +572,11 @@ const file_controller_api_resources_credentiallibraries_v1_credential_library_pr
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1a=\n" +
"\x0fExtensionsEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01BhZfgithub.com/hashicorp/boundary/sdk/pbs/controller/api/resources/credentiallibraries;credentiallibrariesb\x06proto3"
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"~\n" +
"$VaultLdapCredentialLibraryAttributes\x12V\n" +
"\x04path\x18\n" +
" \x01(\v2\x1c.google.protobuf.StringValueB$\xa0\xda)\x01\xc2\xdd)\x1c\n" +
"\x0fattributes.path\x12\tVaultPathR\x04pathBhZfgithub.com/hashicorp/boundary/sdk/pbs/controller/api/resources/credentiallibraries;credentiallibrariesb\x06proto3"
var (
file_controller_api_resources_credentiallibraries_v1_credential_library_proto_rawDescOnce sync.Once
@@ -521,47 +590,50 @@ func file_controller_api_resources_credentiallibraries_v1_credential_library_pro
return file_controller_api_resources_credentiallibraries_v1_credential_library_proto_rawDescData
}
var file_controller_api_resources_credentiallibraries_v1_credential_library_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_controller_api_resources_credentiallibraries_v1_credential_library_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_controller_api_resources_credentiallibraries_v1_credential_library_proto_goTypes = []any{
(*CredentialLibrary)(nil), // 0: controller.api.resources.credentiallibraries.v1.CredentialLibrary
(*VaultCredentialLibraryAttributes)(nil), // 1: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes
(*VaultSSHCertificateCredentialLibraryAttributes)(nil), // 2: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes
nil, // 3: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.CriticalOptionsEntry
nil, // 4: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.ExtensionsEntry
(*scopes.ScopeInfo)(nil), // 5: controller.api.resources.scopes.v1.ScopeInfo
(*wrapperspb.StringValue)(nil), // 6: google.protobuf.StringValue
(*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp
(*structpb.Struct)(nil), // 8: google.protobuf.Struct
(*wrapperspb.UInt32Value)(nil), // 9: google.protobuf.UInt32Value
(*VaultLdapCredentialLibraryAttributes)(nil), // 3: controller.api.resources.credentiallibraries.v1.VaultLdapCredentialLibraryAttributes
nil, // 4: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.CriticalOptionsEntry
nil, // 5: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.ExtensionsEntry
(*scopes.ScopeInfo)(nil), // 6: controller.api.resources.scopes.v1.ScopeInfo
(*wrapperspb.StringValue)(nil), // 7: google.protobuf.StringValue
(*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp
(*structpb.Struct)(nil), // 9: google.protobuf.Struct
(*wrapperspb.UInt32Value)(nil), // 10: google.protobuf.UInt32Value
}
var file_controller_api_resources_credentiallibraries_v1_credential_library_proto_depIdxs = []int32{
5, // 0: controller.api.resources.credentiallibraries.v1.CredentialLibrary.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo
6, // 1: controller.api.resources.credentiallibraries.v1.CredentialLibrary.name:type_name -> google.protobuf.StringValue
6, // 2: controller.api.resources.credentiallibraries.v1.CredentialLibrary.description:type_name -> google.protobuf.StringValue
7, // 3: controller.api.resources.credentiallibraries.v1.CredentialLibrary.created_time:type_name -> google.protobuf.Timestamp
7, // 4: controller.api.resources.credentiallibraries.v1.CredentialLibrary.updated_time:type_name -> google.protobuf.Timestamp
8, // 5: controller.api.resources.credentiallibraries.v1.CredentialLibrary.attributes:type_name -> google.protobuf.Struct
6, // 0: controller.api.resources.credentiallibraries.v1.CredentialLibrary.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo
7, // 1: controller.api.resources.credentiallibraries.v1.CredentialLibrary.name:type_name -> google.protobuf.StringValue
7, // 2: controller.api.resources.credentiallibraries.v1.CredentialLibrary.description:type_name -> google.protobuf.StringValue
8, // 3: controller.api.resources.credentiallibraries.v1.CredentialLibrary.created_time:type_name -> google.protobuf.Timestamp
8, // 4: controller.api.resources.credentiallibraries.v1.CredentialLibrary.updated_time:type_name -> google.protobuf.Timestamp
9, // 5: controller.api.resources.credentiallibraries.v1.CredentialLibrary.attributes:type_name -> google.protobuf.Struct
1, // 6: controller.api.resources.credentiallibraries.v1.CredentialLibrary.vault_credential_library_attributes:type_name -> controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes
2, // 7: controller.api.resources.credentiallibraries.v1.CredentialLibrary.vault_ssh_certificate_credential_library_attributes:type_name -> controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes
1, // 8: controller.api.resources.credentiallibraries.v1.CredentialLibrary.vault_generic_credential_library_attributes:type_name -> controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes
8, // 9: controller.api.resources.credentiallibraries.v1.CredentialLibrary.credential_mapping_overrides:type_name -> google.protobuf.Struct
6, // 10: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes.path:type_name -> google.protobuf.StringValue
6, // 11: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes.http_method:type_name -> google.protobuf.StringValue
6, // 12: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes.http_request_body:type_name -> google.protobuf.StringValue
6, // 13: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.path:type_name -> google.protobuf.StringValue
6, // 14: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.username:type_name -> google.protobuf.StringValue
6, // 15: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.key_type:type_name -> google.protobuf.StringValue
9, // 16: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.key_bits:type_name -> google.protobuf.UInt32Value
6, // 17: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.ttl:type_name -> google.protobuf.StringValue
6, // 18: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.key_id:type_name -> google.protobuf.StringValue
3, // 19: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.critical_options:type_name -> controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.CriticalOptionsEntry
4, // 20: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.extensions:type_name -> controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.ExtensionsEntry
6, // 21: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.additional_valid_principals:type_name -> google.protobuf.StringValue
22, // [22:22] is the sub-list for method output_type
22, // [22:22] is the sub-list for method input_type
22, // [22:22] is the sub-list for extension type_name
22, // [22:22] is the sub-list for extension extendee
0, // [0:22] is the sub-list for field type_name
3, // 9: controller.api.resources.credentiallibraries.v1.CredentialLibrary.vault_ldap_credential_library_attributes:type_name -> controller.api.resources.credentiallibraries.v1.VaultLdapCredentialLibraryAttributes
9, // 10: controller.api.resources.credentiallibraries.v1.CredentialLibrary.credential_mapping_overrides:type_name -> google.protobuf.Struct
7, // 11: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes.path:type_name -> google.protobuf.StringValue
7, // 12: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes.http_method:type_name -> google.protobuf.StringValue
7, // 13: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes.http_request_body:type_name -> google.protobuf.StringValue
7, // 14: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.path:type_name -> google.protobuf.StringValue
7, // 15: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.username:type_name -> google.protobuf.StringValue
7, // 16: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.key_type:type_name -> google.protobuf.StringValue
10, // 17: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.key_bits:type_name -> google.protobuf.UInt32Value
7, // 18: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.ttl:type_name -> google.protobuf.StringValue
7, // 19: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.key_id:type_name -> google.protobuf.StringValue
4, // 20: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.critical_options:type_name -> controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.CriticalOptionsEntry
5, // 21: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.extensions:type_name -> controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.ExtensionsEntry
7, // 22: controller.api.resources.credentiallibraries.v1.VaultSSHCertificateCredentialLibraryAttributes.additional_valid_principals:type_name -> google.protobuf.StringValue
7, // 23: controller.api.resources.credentiallibraries.v1.VaultLdapCredentialLibraryAttributes.path:type_name -> google.protobuf.StringValue
24, // [24:24] is the sub-list for method output_type
24, // [24:24] is the sub-list for method input_type
24, // [24:24] is the sub-list for extension type_name
24, // [24:24] is the sub-list for extension extendee
0, // [0:24] is the sub-list for field type_name
}
func init() { file_controller_api_resources_credentiallibraries_v1_credential_library_proto_init() }
@@ -574,6 +646,7 @@ func file_controller_api_resources_credentiallibraries_v1_credential_library_pro
(*CredentialLibrary_VaultCredentialLibraryAttributes)(nil),
(*CredentialLibrary_VaultSshCertificateCredentialLibraryAttributes)(nil),
(*CredentialLibrary_VaultGenericCredentialLibraryAttributes)(nil),
(*CredentialLibrary_VaultLdapCredentialLibraryAttributes)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
@@ -581,7 +654,7 @@ func file_controller_api_resources_credentiallibraries_v1_credential_library_pro
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_controller_api_resources_credentiallibraries_v1_credential_library_proto_rawDesc), len(file_controller_api_resources_credentiallibraries_v1_credential_library_proto_rawDesc)),
NumEnums: 0,
NumMessages: 5,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},