diff --git a/api/credentiallibraries/credential_library.gen.go b/api/credentiallibraries/credential_library.gen.go index c9357303f..e374637c5 100644 --- a/api/credentiallibraries/credential_library.gen.go +++ b/api/credentiallibraries/credential_library.gen.go @@ -13,17 +13,19 @@ import ( ) type CredentialLibrary struct { - Id string `json:"id,omitempty"` - CredentialStoreId string `json:"credential_store_id,omitempty"` - Scope *scopes.ScopeInfo `json:"scope,omitempty"` - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - CreatedTime time.Time `json:"created_time,omitempty"` - UpdatedTime time.Time `json:"updated_time,omitempty"` - Version uint32 `json:"version,omitempty"` - Type string `json:"type,omitempty"` - Attributes map[string]interface{} `json:"attributes,omitempty"` - AuthorizedActions []string `json:"authorized_actions,omitempty"` + Id string `json:"id,omitempty"` + CredentialStoreId string `json:"credential_store_id,omitempty"` + Scope *scopes.ScopeInfo `json:"scope,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + CreatedTime time.Time `json:"created_time,omitempty"` + UpdatedTime time.Time `json:"updated_time,omitempty"` + Version uint32 `json:"version,omitempty"` + Type string `json:"type,omitempty"` + Attributes map[string]interface{} `json:"attributes,omitempty"` + AuthorizedActions []string `json:"authorized_actions,omitempty"` + CredentialType string `json:"credential_type,omitempty"` + CredentialMappingOverrides map[string]interface{} `json:"credential_mapping_overrides,omitempty"` response *api.Response } diff --git a/api/credentiallibraries/option.gen.go b/api/credentiallibraries/option.gen.go index eb401ca59..c63590351 100644 --- a/api/credentiallibraries/option.gen.go +++ b/api/credentiallibraries/option.gen.go @@ -86,6 +86,30 @@ func DefaultAttributes() Option { } } +func WithCredentialMappingOverrides(inCredentialMappingOverrides map[string]interface{}) Option { + return func(o *options) { + o.postMap["credential_mapping_overrides"] = inCredentialMappingOverrides + } +} + +func DefaultCredentialMappingOverrides() Option { + return func(o *options) { + o.postMap["credential_mapping_overrides"] = nil + } +} + +func WithCredentialType(inCredentialType string) Option { + return func(o *options) { + o.postMap["credential_type"] = inCredentialType + } +} + +func DefaultCredentialType() Option { + return func(o *options) { + o.postMap["credential_type"] = nil + } +} + func WithDescription(inDescription string) Option { return func(o *options) { o.postMap["description"] = inDescription diff --git a/globals/fields.go b/globals/fields.go index eb4ed81bb..be429bc48 100644 --- a/globals/fields.go +++ b/globals/fields.go @@ -70,4 +70,6 @@ const ( EgressCredentialSourceIdsField = "egress_credential_source_ids" EgressCredentialSourcesField = "egress_credential_sources" ConnectionsField = "connections" + CredentialTypeField = "credential_type" + CredentialMappingOverridesField = "credential_mapping_overrides" ) diff --git a/internal/cmd/commands/credentiallibrariescmd/funcs.go b/internal/cmd/commands/credentiallibrariescmd/funcs.go index 3e73fed7d..9292a227c 100644 --- a/internal/cmd/commands/credentiallibrariescmd/funcs.go +++ b/internal/cmd/commands/credentiallibrariescmd/funcs.go @@ -168,6 +168,20 @@ func printItemTable(result api.GenericResult) string { ) } + if item.CredentialType != "" { + ret = append(ret, + "", + " Credential Type:", + fmt.Sprintf(" %v", item.CredentialType), + ) + if len(item.CredentialMappingOverrides) > 0 { + ret = append(ret, + " Credential Mapping Overrides:", + base.WrapMap(4, maxLength, item.CredentialMappingOverrides), + ) + } + } + return base.WrapForHelpText(ret) } diff --git a/internal/cmd/commands/credentiallibrariescmd/vault_funcs.go b/internal/cmd/commands/credentiallibrariescmd/vault_funcs.go index f93f404cc..ae783aa66 100644 --- a/internal/cmd/commands/credentiallibrariescmd/vault_funcs.go +++ b/internal/cmd/commands/credentiallibrariescmd/vault_funcs.go @@ -13,15 +13,19 @@ func init() { } const ( - pathFlagName = "vault-path" - httpMethodFlagName = "vault-http-method" - httpRequestBodyFlagName = "vault-http-request-body" + pathFlagName = "vault-path" + httpMethodFlagName = "vault-http-method" + httpRequestBodyFlagName = "vault-http-request-body" + credentialTypeFlagName = "credential-type" + credentialMappingFlagName = "credential-mapping-override" ) type extraVaultCmdVars struct { - flagPath string - flagHttpMethod string - flagHttpRequestBody string + flagPath string + flagHttpMethod string + flagHttpRequestBody string + flagCredentialType string + flagCredentialMapping []base.CombinedSliceFlagValue } func extraVaultActionsFlagsMapFuncImpl() map[string][]string { @@ -30,6 +34,8 @@ func extraVaultActionsFlagsMapFuncImpl() map[string][]string { pathFlagName, httpMethodFlagName, httpRequestBodyFlagName, + credentialTypeFlagName, + credentialMappingFlagName, }, } flags["update"] = flags["create"] @@ -59,11 +65,24 @@ func extraVaultFlagsFuncImpl(c *VaultCommand, set *base.FlagSets, _ *base.FlagSe Target: &c.flagHttpRequestBody, Usage: "The http request body the library uses to communicate with vault. This can be the value itself, refer to a file on disk (file://) from which the value will be read, or an env var (env://) from which the value will be read.", }) + case credentialTypeFlagName: + f.StringVar(&base.StringVar{ + Name: credentialTypeFlagName, + Target: &c.flagCredentialType, + Usage: "The type of credential this library will issue, defaults to Unspecified.", + }) + case credentialMappingFlagName: + f.CombinationSliceVar(&base.CombinationSliceVar{ + Name: credentialMappingFlagName, + Target: &c.flagCredentialMapping, + KvSplit: true, + Usage: "The credential mapping override.", + }) } } } -func extraVaultFlagHandlingFuncImpl(c *VaultCommand, f *base.FlagSets, opts *[]credentiallibraries.Option) bool { +func extraVaultFlagHandlingFuncImpl(c *VaultCommand, _ *base.FlagSets, opts *[]credentiallibraries.Option) bool { switch c.flagPath { case "": default: @@ -84,11 +103,44 @@ func extraVaultFlagHandlingFuncImpl(c *VaultCommand, f *base.FlagSets, opts *[]c rb, _ := parseutil.ParsePath(c.flagHttpRequestBody) *opts = append(*opts, credentiallibraries.WithVaultCredentialLibraryHttpRequestBody(rb)) } + switch c.flagCredentialType { + case "": + case "null": + *opts = append(*opts, credentiallibraries.DefaultCredentialType()) + default: + *opts = append(*opts, credentiallibraries.WithCredentialType(c.flagCredentialType)) + } + switch len(c.flagCredentialMapping) { + case 0: + case 1: + if len(c.flagCredentialMapping[0].Keys) == 0 && c.flagCredentialMapping[0].Value == "null" { + *opts = append(*opts, credentiallibraries.DefaultCredentialMappingOverrides()) + break + } + fallthrough + default: + mappings := make(map[string]interface{}, len(c.flagCredentialMapping)) + for _, mapping := range c.flagCredentialMapping { + switch { + case len(mapping.Keys) != 1 || mapping.Keys[0] == "": + // mapping override does not support key segments (e.g. 'x.y=z') + c.UI.Error("Credential mapping override must be in the format 'key=value', 'key=null' to clear field or 'null' to clear all.") + return false + case mapping.Value == "null": + // user provided 'key=null' indicating the field specific override should + // be cleared, set map value to nil + mappings[mapping.Keys[0]] = nil + default: + mappings[mapping.Keys[0]] = mapping.Value + } + } + *opts = append(*opts, credentiallibraries.WithCredentialMappingOverrides(mappings)) + } return true } -func (c *VaultCommand) extraVaultHelpFunc(helpMap map[string]func() string) string { +func (c *VaultCommand) extraVaultHelpFunc(_ map[string]func() string) string { var helpStr string switch c.Func { case "create": diff --git a/internal/credential/vault/credential_library_test.go b/internal/credential/vault/credential_library_test.go index 32685ac8a..c6e165b7e 100644 --- a/internal/credential/vault/credential_library_test.go +++ b/internal/credential/vault/credential_library_test.go @@ -226,6 +226,27 @@ func TestCredentialLibrary_New(t *testing.T) { }, }, }, + { + name: "credential-type-with-userpass-mapping", + args: args{ + storeId: cs.PublicId, + vaultPath: "vault/path", + opts: []Option{ + WithMethod(MethodGet), + WithCredentialType(credential.UserPasswordType), + WithMappingOverride(NewUserPasswordOverride(WithOverrideUsernameAttribute("test"))), + }, + }, + want: &CredentialLibrary{ + MappingOverride: NewUserPasswordOverride(WithOverrideUsernameAttribute("test")), + CredentialLibrary: &store.CredentialLibrary{ + StoreId: cs.PublicId, + VaultPath: "vault/path", + HttpMethod: string(MethodGet), + CredentialType: string(credential.UserPasswordType), + }, + }, + }, } for _, tt := range tests { diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index 2f7913e33..a37a637f7 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -3923,6 +3923,14 @@ }, "description": "Output only. The available actions on this resource for this user.", "readOnly": true + }, + "credential_type": { + "type": "string", + "title": "The type of credential this library will issue, defaults to Unspecified" + }, + "credential_mapping_overrides": { + "type": "object", + "title": "The credential mapping overrides" } }, "title": "CredentialLibrary contains all fields related to an Credential Library resource" diff --git a/internal/proto/local/controller/api/resources/credentiallibraries/v1/credential_library.proto b/internal/proto/local/controller/api/resources/credentiallibraries/v1/credential_library.proto index 7fca04277..65d688e04 100644 --- a/internal/proto/local/controller/api/resources/credentiallibraries/v1/credential_library.proto +++ b/internal/proto/local/controller/api/resources/credentiallibraries/v1/credential_library.proto @@ -45,6 +45,12 @@ message CredentialLibrary { // Output only. The available actions on this resource for this user. repeated string authorized_actions = 300 [json_name = "authorized_actions"]; + + // The type of credential this library will issue, defaults to Unspecified + string credential_type = 310 [json_name = "credential_type", (custom_options.v1.generate_sdk_option) = true]; + + // The credential mapping overrides + google.protobuf.Struct credential_mapping_overrides = 320 [json_name = "credential_mapping_overrides", (custom_options.v1.generate_sdk_option) = true]; } // The attributes of a vault typed Credential Library. diff --git a/internal/servers/controller/handlers/credentiallibraries/credentiallibrary_service.go b/internal/servers/controller/handlers/credentiallibraries/credentiallibrary_service.go index 31dc178eb..1667e4d62 100644 --- a/internal/servers/controller/handlers/credentiallibraries/credentiallibrary_service.go +++ b/internal/servers/controller/handlers/credentiallibraries/credentiallibrary_service.go @@ -21,6 +21,7 @@ import ( pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/credentiallibraries" "github.com/hashicorp/go-secure-stdlib/strutil" "google.golang.org/grpc/codes" + "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/wrapperspb" ) @@ -30,6 +31,12 @@ const ( httpRequestBodyField = "attributes.http_request_body" ) +// Credential mapping override attributes +const ( + usernameAttribute string = "username_attribute" + passwordAttribute string = "password_attribute" +) + var ( maskManager handlers.MaskManager @@ -463,13 +470,36 @@ func toProto(in credential.Library, opt ...handlers.Option) (*pb.CredentialLibra if outputFields.Has(globals.AuthorizedActionsField) { out.AuthorizedActions = opts.WithAuthorizedActions } - if outputFields.Has(globals.AttributesField) { - switch credential.SubtypeFromId(in.GetPublicId()) { - case vault.Subtype: - vaultIn, ok := in.(*vault.CredentialLibrary) - if !ok { - return nil, errors.NewDeprecated(errors.Internal, op, "unable to cast to vault credential library") + switch credential.SubtypeFromId(in.GetPublicId()) { + case vault.Subtype: + vaultIn, ok := in.(*vault.CredentialLibrary) + if !ok { + return nil, errors.NewDeprecated(errors.Internal, op, "unable to cast to vault credential library") + } + + if outputFields.Has(globals.CredentialTypeField) && vaultIn.GetCredentialType() != string(credential.UnspecifiedType) { + out.CredentialType = vaultIn.GetCredentialType() + if outputFields.Has(globals.CredentialMappingOverridesField) && vaultIn.MappingOverride != nil { + m := make(map[string]interface{}) + switch mapping := vaultIn.MappingOverride.(type) { + case *vault.UserPasswordOverride: + if mapping.UsernameAttribute != "" { + m[usernameAttribute] = mapping.UsernameAttribute + } + if mapping.PasswordAttribute != "" { + m[passwordAttribute] = mapping.PasswordAttribute + } + } + if len(m) > 0 { + mp, err := structpb.NewStruct(m) + if err != nil { + return nil, errors.NewDeprecated(errors.Internal, op, "creating proto struct for mapping override") + } + out.CredentialMappingOverrides = mp + } } + } + if outputFields.Has(globals.AttributesField) { attrs := &pb.VaultCredentialLibraryAttributes{ Path: wrapperspb.String(vaultIn.GetVaultPath()), } @@ -511,6 +541,23 @@ func toStorageVaultLibrary(storeId string, in *pb.CredentialLibrary) (out *vault opts = append(opts, vault.WithRequestBody([]byte(attrs.GetHttpRequestBody().GetValue()))) } + credentialType := credential.Type(in.GetCredentialType()) + switch credentialType { + case credential.UserPasswordType: + opts = append(opts, vault.WithCredentialType(credentialType)) + overrides := in.CredentialMappingOverrides.AsMap() + var mapOpts []vault.Option + if username := overrides[usernameAttribute]; username != nil { + mapOpts = append(mapOpts, vault.WithOverrideUsernameAttribute(username.(string))) + } + if password := overrides[passwordAttribute]; password != nil { + mapOpts = append(mapOpts, vault.WithOverridePasswordAttribute(password.(string))) + } + if len(mapOpts) > 0 { + opts = append(opts, vault.WithMappingOverride(vault.NewUserPasswordOverride(mapOpts...))) + } + } + cs, err := vault.NewCredentialLibrary(storeId, attrs.GetPath().GetValue(), opts...) if err != nil { return nil, errors.WrapDeprecated(err, op, errors.WithMsg("unable to build credential library")) @@ -549,6 +596,7 @@ func validateCreateRequest(req *pbs.CreateCredentialLibraryRequest) error { if b := attrs.GetHttpRequestBody(); b != nil && strings.ToUpper(attrs.GetHttpMethod().GetValue()) != "POST" { badFields[httpRequestBodyField] = fmt.Sprintf("Field can only be set if %q is set to the value 'POST'.", httpMethodField) } + validateMapping(badFields, req.GetItem().GetCredentialType(), req.GetItem().CredentialMappingOverrides.AsMap()) default: badFields[globals.CredentialStoreIdField] = "This field must be a valid credential store id." } @@ -600,3 +648,30 @@ func validateListRequest(req *pbs.ListCredentialLibrariesRequest) error { } return nil } + +func validateMapping(badFields map[string]string, credentialType string, overrides map[string]interface{}) { + validFields := make(map[string]bool) + switch credential.Type(credentialType) { + case "": + if len(overrides) > 0 { + badFields[globals.CredentialMappingOverridesField] = fmt.Sprintf("This field can only be set if %q is set", globals.CredentialTypeField) + } + return + case credential.UserPasswordType: + validFields[usernameAttribute] = true + validFields[passwordAttribute] = true + default: + badFields[globals.CredentialTypeField] = fmt.Sprintf("Unknown credential type %q", credentialType) + return + } + + for k, v := range overrides { + if ok := validFields[k]; !ok { + badFields[globals.CredentialMappingOverridesField+"."+k] = fmt.Sprintf("Invalid mapping override for credential type %q", credentialType) + continue + } + if _, ok := v.(string); v != nil && !ok { + badFields[globals.CredentialMappingOverridesField+"."+k] = fmt.Sprintf("Mapping value must be a string or a null to clear, got %T", v) + } + } +} diff --git a/internal/servers/controller/handlers/credentiallibraries/credentiallibrary_service_test.go b/internal/servers/controller/handlers/credentiallibraries/credentiallibrary_service_test.go index 681294a1a..3e1e7e5b9 100644 --- a/internal/servers/controller/handlers/credentiallibraries/credentiallibrary_service_test.go +++ b/internal/servers/controller/handlers/credentiallibraries/credentiallibrary_service_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/boundary/internal/credential" "github.com/hashicorp/boundary/internal/credential/vault" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" @@ -326,6 +327,47 @@ func TestCreate(t *testing.T) { res: nil, err: handlers.ApiErrorWithCode(codes.InvalidArgument), }, + { + name: "Invalid credential type", + req: &pbs.CreateCredentialLibraryRequest{Item: &pb.CredentialLibrary{ + CredentialStoreId: store.GetPublicId(), + Attributes: func() *structpb.Struct { + attrs, err := handlers.ProtoToStruct(&pb.VaultCredentialLibraryAttributes{ + Path: wrapperspb.String("something"), + }) + require.NoError(t, err) + return attrs + }(), + CredentialType: "fake-type", + }}, + res: nil, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + { + name: "Invalid user_password mapping", + req: &pbs.CreateCredentialLibraryRequest{Item: &pb.CredentialLibrary{ + CredentialStoreId: store.GetPublicId(), + Attributes: func() *structpb.Struct { + attrs, err := handlers.ProtoToStruct(&pb.VaultCredentialLibraryAttributes{ + Path: wrapperspb.String("something"), + }) + require.NoError(t, err) + return attrs + }(), + CredentialType: string(credential.UserPasswordType), + CredentialMappingOverrides: func() *structpb.Struct { + v := map[string]interface{}{ + usernameAttribute: "user-test", + "invalid": "invalid-test", + } + ret, err := structpb.NewStruct(v) + require.NoError(t, err) + return ret + }(), + }}, + res: nil, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, { name: "Using POST method", req: &pbs.CreateCredentialLibraryRequest{Item: &pb.CredentialLibrary{ @@ -403,6 +445,151 @@ func TestCreate(t *testing.T) { }, }, }, + { + name: "Create a valid vault CredentialLibrary user_password type", + req: &pbs.CreateCredentialLibraryRequest{Item: &pb.CredentialLibrary{ + CredentialStoreId: store.GetPublicId(), + Attributes: func() *structpb.Struct { + attrs, err := handlers.ProtoToStruct(&pb.VaultCredentialLibraryAttributes{ + Path: wrapperspb.String("something"), + }) + require.NoError(t, err) + return attrs + }(), + CredentialType: string(credential.UserPasswordType), + }}, + idPrefix: vault.CredentialLibraryPrefix + "_", + res: &pbs.CreateCredentialLibraryResponse{ + Uri: fmt.Sprintf("credential-libraries/%s_", vault.CredentialLibraryPrefix), + 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.Subtype.String(), + Attributes: func() *structpb.Struct { + attrs, err := handlers.ProtoToStruct(&pb.VaultCredentialLibraryAttributes{ + Path: wrapperspb.String("something"), + HttpMethod: wrapperspb.String("GET"), + }) + require.NoError(t, err) + return attrs + }(), + CredentialType: string(credential.UserPasswordType), + AuthorizedActions: testAuthorizedActions, + }, + }, + }, + { + name: "Create a valid vault CredentialLibrary user_password type with username mapping", + req: &pbs.CreateCredentialLibraryRequest{Item: &pb.CredentialLibrary{ + CredentialStoreId: store.GetPublicId(), + Attributes: func() *structpb.Struct { + attrs, err := handlers.ProtoToStruct(&pb.VaultCredentialLibraryAttributes{ + Path: wrapperspb.String("something"), + }) + require.NoError(t, err) + return attrs + }(), + CredentialMappingOverrides: func() *structpb.Struct { + v := map[string]interface{}{ + usernameAttribute: "user-test", + } + ret, err := structpb.NewStruct(v) + require.NoError(t, err) + return ret + }(), + CredentialType: string(credential.UserPasswordType), + }}, + idPrefix: vault.CredentialLibraryPrefix + "_", + res: &pbs.CreateCredentialLibraryResponse{ + Uri: fmt.Sprintf("credential-libraries/%s_", vault.CredentialLibraryPrefix), + 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.Subtype.String(), + Attributes: func() *structpb.Struct { + attrs, err := handlers.ProtoToStruct(&pb.VaultCredentialLibraryAttributes{ + Path: wrapperspb.String("something"), + HttpMethod: wrapperspb.String("GET"), + }) + require.NoError(t, err) + return attrs + }(), + CredentialType: string(credential.UserPasswordType), + CredentialMappingOverrides: func() *structpb.Struct { + v := map[string]interface{}{ + usernameAttribute: "user-test", + } + ret, err := structpb.NewStruct(v) + require.NoError(t, err) + return ret + }(), + AuthorizedActions: testAuthorizedActions, + }, + }, + }, + { + name: "Create a valid vault CredentialLibrary user_password type with username/password mapping", + req: &pbs.CreateCredentialLibraryRequest{Item: &pb.CredentialLibrary{ + CredentialStoreId: store.GetPublicId(), + Attributes: func() *structpb.Struct { + attrs, err := handlers.ProtoToStruct(&pb.VaultCredentialLibraryAttributes{ + Path: wrapperspb.String("something"), + }) + require.NoError(t, err) + return attrs + }(), + CredentialMappingOverrides: func() *structpb.Struct { + v := map[string]interface{}{ + usernameAttribute: "user-test", + passwordAttribute: "pass-test", + } + ret, err := structpb.NewStruct(v) + require.NoError(t, err) + return ret + }(), + CredentialType: string(credential.UserPasswordType), + }}, + idPrefix: vault.CredentialLibraryPrefix + "_", + res: &pbs.CreateCredentialLibraryResponse{ + Uri: fmt.Sprintf("credential-libraries/%s_", vault.CredentialLibraryPrefix), + 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.Subtype.String(), + Attributes: func() *structpb.Struct { + attrs, err := handlers.ProtoToStruct(&pb.VaultCredentialLibraryAttributes{ + Path: wrapperspb.String("something"), + HttpMethod: wrapperspb.String("GET"), + }) + require.NoError(t, err) + return attrs + }(), + CredentialType: string(credential.UserPasswordType), + CredentialMappingOverrides: func() *structpb.Struct { + v := map[string]interface{}{ + usernameAttribute: "user-test", + passwordAttribute: "pass-test", + } + ret, err := structpb.NewStruct(v) + require.NoError(t, err) + return ret + }(), + AuthorizedActions: testAuthorizedActions, + }, + }, + }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { diff --git a/sdk/pbs/controller/api/resources/credentiallibraries/credential_library.pb.go b/sdk/pbs/controller/api/resources/credentiallibraries/credential_library.pb.go index a042456b7..d9dcac8fa 100644 --- a/sdk/pbs/controller/api/resources/credentiallibraries/credential_library.pb.go +++ b/sdk/pbs/controller/api/resources/credentiallibraries/credential_library.pb.go @@ -54,6 +54,10 @@ type CredentialLibrary struct { Attributes *structpb.Struct `protobuf:"bytes,100,opt,name=attributes,proto3" json:"attributes,omitempty"` // 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"` + // The type of credential this library will issue, defaults to Unspecified + CredentialType string `protobuf:"bytes,310,opt,name=credential_type,proto3" json:"credential_type,omitempty"` + // The credential mapping overrides + CredentialMappingOverrides *structpb.Struct `protobuf:"bytes,320,opt,name=credential_mapping_overrides,proto3" json:"credential_mapping_overrides,omitempty"` } func (x *CredentialLibrary) Reset() { @@ -165,6 +169,20 @@ func (x *CredentialLibrary) GetAuthorizedActions() []string { return nil } +func (x *CredentialLibrary) GetCredentialType() string { + if x != nil { + return x.CredentialType + } + return "" +} + +func (x *CredentialLibrary) GetCredentialMappingOverrides() *structpb.Struct { + if x != nil { + return x.CredentialMappingOverrides + } + return nil +} + // The attributes of a vault typed Credential Library. type VaultCredentialLibraryAttributes struct { state protoimpl.MessageState @@ -254,7 +272,7 @@ var file_controller_api_resources_credentiallibraries_v1_credential_library_prot 0x63, 0x6f, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe4, 0x04, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x64, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf9, 0x05, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, @@ -292,37 +310,47 @@ var file_controller_api_resources_credentiallibraries_v1_credential_library_prot 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xac, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xee, 0x02, - 0x0a, 0x20, 0x56, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x73, 0x12, 0x56, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x24, - 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x1c, 0x0a, 0x0f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x73, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x12, 0x09, 0x56, 0x61, 0x75, 0x6c, 0x74, - 0x50, 0x61, 0x74, 0x68, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x6c, 0x0a, 0x0b, 0x68, 0x74, - 0x74, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2c, 0xa0, - 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x24, 0x0a, 0x16, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, - 0x0a, 0x48, 0x74, 0x74, 0x70, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0b, 0x68, 0x74, 0x74, - 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x83, 0x01, 0x0a, 0x11, 0x68, 0x74, 0x74, - 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x1e, + 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x0a, + 0x0f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x18, 0xb6, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0xa0, 0xda, 0x29, 0x01, 0x52, 0x0f, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x62, + 0x0a, 0x1c, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x18, 0xc0, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x04, + 0xa0, 0xda, 0x29, 0x01, 0x52, 0x1c, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, + 0x65, 0x73, 0x22, 0xee, 0x02, 0x0a, 0x20, 0x56, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x41, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x56, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x42, 0x24, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x1c, 0x0a, 0x0f, 0x61, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x12, 0x09, + 0x56, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x61, 0x74, 0x68, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, + 0x6c, 0x0a, 0x0b, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x42, 0x37, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x2f, 0x0a, 0x1c, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x0f, 0x48, 0x74, 0x74, 0x70, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x11, 0x68, 0x74, 0x74, - 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x68, - 0x5a, 0x66, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, - 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x62, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x69, 0x62, 0x72, 0x61, - 0x72, 0x69, 0x65, 0x73, 0x3b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, - 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x75, 0x65, 0x42, 0x2c, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x24, 0x0a, 0x16, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x6d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x12, 0x0a, 0x48, 0x74, 0x74, 0x70, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x52, 0x0b, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x83, 0x01, + 0x0a, 0x11, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x62, + 0x6f, 0x64, 0x79, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x37, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, + 0x2f, 0x0a, 0x1c, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x68, 0x74, + 0x74, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x12, + 0x0f, 0x48, 0x74, 0x74, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6f, 0x64, 0x79, + 0x52, 0x11, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x62, + 0x6f, 0x64, 0x79, 0x42, 0x68, 0x5a, 0x66, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, + 0x64, 0x61, 0x72, 0x79, 0x2f, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x62, 0x73, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x3b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -347,20 +375,21 @@ var file_controller_api_resources_credentiallibraries_v1_credential_library_prot (*structpb.Struct)(nil), // 5: google.protobuf.Struct } var file_controller_api_resources_credentiallibraries_v1_credential_library_proto_depIdxs = []int32{ - 2, // 0: controller.api.resources.credentiallibraries.v1.CredentialLibrary.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo - 3, // 1: controller.api.resources.credentiallibraries.v1.CredentialLibrary.name:type_name -> google.protobuf.StringValue - 3, // 2: controller.api.resources.credentiallibraries.v1.CredentialLibrary.description:type_name -> google.protobuf.StringValue - 4, // 3: controller.api.resources.credentiallibraries.v1.CredentialLibrary.created_time:type_name -> google.protobuf.Timestamp - 4, // 4: controller.api.resources.credentiallibraries.v1.CredentialLibrary.updated_time:type_name -> google.protobuf.Timestamp - 5, // 5: controller.api.resources.credentiallibraries.v1.CredentialLibrary.attributes:type_name -> google.protobuf.Struct - 3, // 6: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes.path:type_name -> google.protobuf.StringValue - 3, // 7: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes.http_method:type_name -> google.protobuf.StringValue - 3, // 8: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes.http_request_body:type_name -> google.protobuf.StringValue - 9, // [9:9] is the sub-list for method output_type - 9, // [9:9] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 2, // 0: controller.api.resources.credentiallibraries.v1.CredentialLibrary.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo + 3, // 1: controller.api.resources.credentiallibraries.v1.CredentialLibrary.name:type_name -> google.protobuf.StringValue + 3, // 2: controller.api.resources.credentiallibraries.v1.CredentialLibrary.description:type_name -> google.protobuf.StringValue + 4, // 3: controller.api.resources.credentiallibraries.v1.CredentialLibrary.created_time:type_name -> google.protobuf.Timestamp + 4, // 4: controller.api.resources.credentiallibraries.v1.CredentialLibrary.updated_time:type_name -> google.protobuf.Timestamp + 5, // 5: controller.api.resources.credentiallibraries.v1.CredentialLibrary.attributes:type_name -> google.protobuf.Struct + 5, // 6: controller.api.resources.credentiallibraries.v1.CredentialLibrary.credential_mapping_overrides:type_name -> google.protobuf.Struct + 3, // 7: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes.path:type_name -> google.protobuf.StringValue + 3, // 8: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes.http_method:type_name -> google.protobuf.StringValue + 3, // 9: controller.api.resources.credentiallibraries.v1.VaultCredentialLibraryAttributes.http_request_body:type_name -> google.protobuf.StringValue + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name } func init() { file_controller_api_resources_credentiallibraries_v1_credential_library_proto_init() }