2022-08-25 14:37:22 -04:00
// Copyright (c) HashiCorp, Inc.
2021-06-22 22:26:26 -04:00
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2021-06-22 22:26:26 -04:00
package credentialstores
import (
"context"
"encoding/base64"
"encoding/pem"
"fmt"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/credential"
2022-05-18 20:20:45 -07:00
"github.com/hashicorp/boundary/internal/credential/static"
2021-06-22 22:26:26 -04:00
"github.com/hashicorp/boundary/internal/credential/vault"
"github.com/hashicorp/boundary/internal/credential/vault/store"
2022-05-09 12:45:10 -07:00
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
"github.com/hashicorp/boundary/internal/daemon/controller/common"
"github.com/hashicorp/boundary/internal/daemon/controller/common/scopeids"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentiallibraries"
2022-05-18 20:20:45 -07:00
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentials"
2021-06-22 22:26:26 -04:00
"github.com/hashicorp/boundary/internal/errors"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
2023-12-06 09:45:44 -08:00
"github.com/hashicorp/boundary/internal/listtoken"
"github.com/hashicorp/boundary/internal/pagination"
2021-06-22 22:26:26 -04:00
"github.com/hashicorp/boundary/internal/perms"
"github.com/hashicorp/boundary/internal/requests"
"github.com/hashicorp/boundary/internal/types/action"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/internal/types/scope"
2022-04-06 15:29:00 -04:00
"github.com/hashicorp/boundary/internal/types/subtypes"
2021-08-26 10:44:41 -04:00
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/credentialstores"
2023-12-06 09:45:44 -08:00
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
2021-06-22 22:26:26 -04:00
"google.golang.org/grpc/codes"
2022-05-18 20:20:45 -07:00
"google.golang.org/protobuf/types/known/structpb"
2021-06-22 22:26:26 -04:00
"google.golang.org/protobuf/types/known/wrapperspb"
)
const (
2022-07-22 09:13:49 -04:00
vaultTokenField = "attributes.token"
vaultTokenHmacField = "attributes.token_hmac"
vaultWorkerFilterField = "attributes.worker_filter"
caCertsField = "attributes.ca_cert"
clientCertField = "attributes.client_certificate"
clientCertKeyField = "attributes.certificate_key"
domain = "credential"
2021-06-22 22:26:26 -04:00
)
var (
maskManager handlers . MaskManager
// IdActions contains the set of actions that can be performed on
// individual resources
2023-10-31 13:44:17 +00:00
IdActions = action . NewActionSet (
2021-06-22 22:26:26 -04:00
action . NoOp ,
action . Read ,
action . Update ,
action . Delete ,
2023-10-31 13:44:17 +00:00
)
2021-06-22 22:26:26 -04:00
// CollectionActions contains the set of actions that can be performed on
// this collection
2023-10-31 13:44:17 +00:00
CollectionActions = action . NewActionSet (
2021-06-22 22:26:26 -04:00
action . Create ,
action . List ,
2023-10-31 13:44:17 +00:00
)
2021-06-22 22:26:26 -04:00
2022-05-18 20:20:45 -07:00
vaultCollectionTypeMap = map [ resource . Type ] action . ActionSet {
2021-06-22 22:26:26 -04:00
resource . CredentialLibrary : credentiallibraries . CollectionActions ,
}
2022-05-18 20:20:45 -07:00
staticCollectionTypeMap = map [ resource . Type ] action . ActionSet {
resource . Credential : credentials . CollectionActions ,
}
2022-07-22 09:13:49 -04:00
validateVaultWorkerFilterFn = vaultWorkerFilterUnsupported
vaultWorkerFilterToProto = false
2021-06-22 22:26:26 -04:00
)
2022-07-22 09:13:49 -04:00
func vaultWorkerFilterUnsupported ( string ) error {
return fmt . Errorf ( "Worker Filter field is not supported in OSS" )
}
2021-06-22 22:26:26 -04:00
func init () {
var err error
2023-06-06 17:09:08 -04:00
if maskManager , err = handlers . NewMaskManager (
context . Background (),
handlers . MaskDestination { & store . CredentialStore {}, & store . Token {}, & store . ClientCertificate {}},
handlers . MaskSource { & pb . CredentialStore {}, & pb . VaultCredentialStoreAttributes {}},
); err != nil {
2021-06-22 22:26:26 -04:00
panic ( err )
}
2023-10-11 18:26:16 +00:00
// TODO: refactor to remove IdActionsMap and CollectionActions package variables
action . RegisterResource ( resource . CredentialStore , IdActions , CollectionActions )
2021-06-22 22:26:26 -04:00
}
// Service handles request as described by the pbs.CredentialStoreServiceServer interface.
type Service struct {
2022-08-30 14:22:10 -04:00
pbs . UnsafeCredentialStoreServiceServer
2021-06-22 22:26:26 -04:00
2022-05-18 20:20:45 -07:00
iamRepoFn common . IamRepoFactory
vaultRepoFn common . VaultCredentialRepoFactory
staticRepoFn common . StaticCredentialRepoFactory
2023-12-06 09:45:44 -08:00
storeRepoFn common . CredentialStoreRepoFactory
maxPageSize uint
2021-06-22 22:26:26 -04:00
}
2022-08-30 14:22:10 -04:00
var _ pbs . CredentialStoreServiceServer = ( * Service )( nil )
2021-06-22 22:26:26 -04:00
// NewService returns a credential store service which handles credential store related requests to boundary.
2022-05-18 20:20:45 -07:00
func NewService (
2022-08-25 14:37:22 -04:00
ctx context . Context ,
2023-12-06 09:45:44 -08:00
iamRepo common . IamRepoFactory ,
2022-05-18 20:20:45 -07:00
vaultRepo common . VaultCredentialRepoFactory ,
staticRepo common . StaticCredentialRepoFactory ,
2023-12-06 09:45:44 -08:00
storeRepoFn common . CredentialStoreRepoFactory ,
maxPageSize uint ,
2022-05-18 20:20:45 -07:00
) ( Service , error ) {
2021-06-22 22:26:26 -04:00
const op = "credentialstores.NewService"
if iamRepo == nil {
2022-08-25 14:37:22 -04:00
return Service {}, errors . New ( ctx , errors . InvalidParameter , op , "missing iam repository" )
2021-06-22 22:26:26 -04:00
}
2022-05-18 20:20:45 -07:00
if vaultRepo == nil {
2022-08-25 14:37:22 -04:00
return Service {}, errors . New ( ctx , errors . InvalidParameter , op , "missing vault credential repository" )
2021-06-22 22:26:26 -04:00
}
2022-05-18 20:20:45 -07:00
if staticRepo == nil {
2022-08-25 14:37:22 -04:00
return Service {}, errors . New ( ctx , errors . InvalidParameter , op , "missing static credential repository" )
2022-05-18 20:20:45 -07:00
}
2023-12-06 09:45:44 -08:00
if storeRepoFn == nil {
return Service {}, errors . New ( ctx , errors . InvalidParameter , op , "missing credential store repo" )
}
if maxPageSize == 0 {
maxPageSize = uint ( globals . DefaultMaxPageSize )
}
return Service {
iamRepoFn : iamRepo ,
vaultRepoFn : vaultRepo ,
staticRepoFn : staticRepo ,
storeRepoFn : storeRepoFn ,
maxPageSize : maxPageSize ,
}, nil
2021-06-22 22:26:26 -04:00
}
// ListCredentialStores implements the interface pbs.CredentialStoreServiceServer
func ( s Service ) ListCredentialStores ( ctx context . Context , req * pbs . ListCredentialStoresRequest ) ( * pbs . ListCredentialStoresResponse , error ) {
2023-12-06 09:45:44 -08:00
const op = "credentialstores.(Service).ListCredentialStores"
2023-06-06 17:09:08 -04:00
if err := validateListRequest ( ctx , req ); err != nil {
2023-12-06 09:45:44 -08:00
return nil , errors . Wrap ( ctx , err , op )
2021-06-22 22:26:26 -04:00
}
authResults := s . authResult ( ctx , req . GetScopeId (), action . List )
if authResults . Error != nil {
// If it's forbidden, and it's a recursive request, and they're
// successfully authenticated but just not authorized, keep going as we
2021-09-02 12:55:04 -04:00
// may have authorization on downstream scopes. Or, if they've not
// authenticated, still process in case u_anon has permissions.
if ( authResults . Error == handlers . ForbiddenError () || authResults . Error == handlers . UnauthenticatedError ()) &&
2021-06-22 22:26:26 -04:00
req . GetRecursive () &&
authResults . AuthenticationFinished {
} else {
return nil , authResults . Error
}
}
scopeIds , scopeInfoMap , err := scopeids . GetListingScopeIds (
2022-04-29 09:52:01 -04:00
ctx , s . iamRepoFn , authResults , req . GetScopeId (), resource . CredentialStore , req . GetRecursive ())
2021-06-22 22:26:26 -04:00
if err != nil {
2023-12-06 09:45:44 -08:00
return nil , errors . Wrap ( ctx , err , op )
2021-06-22 22:26:26 -04:00
}
2023-12-06 09:45:44 -08:00
pageSize := int ( s . maxPageSize )
// Use the requested page size only if it is smaller than
// the configured max.
if req . GetPageSize () != 0 && uint ( req . GetPageSize ()) < s . maxPageSize {
pageSize = int ( req . GetPageSize ())
}
var filterItemFn func ( ctx context . Context , item credential . Store ) ( bool , error )
switch {
case req . GetFilter () != "" :
// Only use a filter if we need to
filter , err := handlers . NewFilter ( ctx , req . GetFilter ())
if err != nil {
return nil , err
}
// TODO: replace the need for this function with some way to convert the `filter`
// to a domain type. This would allow filtering to happen in the domain, and we could
// remove this callback altogether.
filterItemFn = func ( ctx context . Context , item credential . Store ) ( bool , error ) {
outputOpts , ok , err := newOutputOpts ( ctx , item , authResults , scopeInfoMap )
if err != nil {
return false , err
}
if ! ok {
return false , nil
}
pbItem , err := toProto ( ctx , item , outputOpts ... )
if err != nil {
return false , err
}
2021-06-22 22:26:26 -04:00
2023-12-06 09:45:44 -08:00
filterable , err := subtypes . Filterable ( ctx , pbItem )
if err != nil {
return false , err
}
return filter . Match ( filterable ), nil
}
default :
filterItemFn = func ( ctx context . Context , item credential . Store ) ( bool , error ) {
return true , nil
}
2021-06-22 22:26:26 -04:00
}
2023-12-06 09:45:44 -08:00
repo , err := s . storeRepoFn ()
2021-06-22 22:26:26 -04:00
if err != nil {
2023-12-06 09:45:44 -08:00
return nil , errors . Wrap ( ctx , err , op )
2021-06-22 22:26:26 -04:00
}
2023-12-06 09:45:44 -08:00
grantsHash , err := authResults . GrantsHash ( ctx )
if err != nil {
return nil , errors . Wrap ( ctx , err , op )
2021-06-22 22:26:26 -04:00
}
2023-12-06 09:45:44 -08:00
var listResp * pagination . ListResponse [ credential . Store ]
var sortBy string
if req . GetListToken () == "" {
sortBy = "created_time"
listResp , err = credential . ListStores ( ctx , grantsHash , pageSize , filterItemFn , repo , scopeIds )
if err != nil {
return nil , err
2021-06-22 22:26:26 -04:00
}
2023-12-06 09:45:44 -08:00
} else {
listToken , err := handlers . ParseListToken ( ctx , req . GetListToken (), resource . CredentialStore , grantsHash )
if err != nil {
return nil , err
2021-06-22 22:26:26 -04:00
}
2023-12-06 09:45:44 -08:00
switch st := listToken . Subtype .( type ) {
case * listtoken . PaginationToken :
sortBy = "created_time"
listResp , err = credential . ListStoresPage ( ctx , grantsHash , pageSize , filterItemFn , listToken , repo , scopeIds )
if err != nil {
return nil , err
}
case * listtoken . StartRefreshToken :
sortBy = "updated_time"
listResp , err = credential . ListStoresRefresh ( ctx , grantsHash , pageSize , filterItemFn , listToken , repo , scopeIds )
2021-06-22 22:26:26 -04:00
if err != nil {
return nil , err
}
2023-12-06 09:45:44 -08:00
case * listtoken . RefreshToken :
sortBy = "updated_time"
listResp , err = credential . ListStoresRefreshPage ( ctx , grantsHash , pageSize , filterItemFn , listToken , repo , scopeIds )
if err != nil {
return nil , err
}
default :
return nil , handlers . ApiErrorWithCodeAndMessage ( codes . InvalidArgument , "unexpected list token subtype: %T" , st )
2021-06-22 22:26:26 -04:00
}
2023-12-06 09:45:44 -08:00
}
2021-06-22 22:26:26 -04:00
2023-12-06 09:45:44 -08:00
finalItems := make ([] * pb . CredentialStore , 0 , len ( listResp . Items ))
for _ , item := range listResp . Items {
outputOpts , ok , err := newOutputOpts ( ctx , item , authResults , scopeInfoMap )
2021-06-22 22:26:26 -04:00
if err != nil {
2023-12-06 09:45:44 -08:00
return nil , errors . Wrap ( ctx , err , op )
2021-06-22 22:26:26 -04:00
}
2023-12-06 09:45:44 -08:00
if ! ok {
continue
}
pbItem , err := toProto ( ctx , item , outputOpts ... )
if err != nil {
return nil , errors . Wrap ( ctx , err , op )
}
finalItems = append ( finalItems , pbItem )
}
respType := "delta"
if listResp . CompleteListing {
respType = "complete"
}
resp := & pbs . ListCredentialStoresResponse {
Items : finalItems ,
EstItemCount : uint32 ( listResp . EstimatedItemCount ),
RemovedIds : listResp . DeletedIds ,
ResponseType : respType ,
SortBy : sortBy ,
SortDir : "desc" ,
}
2021-06-22 22:26:26 -04:00
2023-12-06 09:45:44 -08:00
if listResp . ListToken != nil {
resp . ListToken , err = handlers . MarshalListToken ( ctx , listResp . ListToken , pbs . ResourceType_RESOURCE_TYPE_CREDENTIAL_STORE )
2022-04-07 13:31:04 -04:00
if err != nil {
return nil , err
}
2021-06-22 22:26:26 -04:00
}
2023-12-06 09:45:44 -08:00
return resp , nil
2021-06-22 22:26:26 -04:00
}
// GetCredentialStore implements the interface pbs.CredentialStoreServiceServer.
func ( s Service ) GetCredentialStore ( ctx context . Context , req * pbs . GetCredentialStoreRequest ) ( * pbs . GetCredentialStoreResponse , error ) {
const op = "credentialstores.(Service).GetCredentialStore"
if err := validateGetRequest ( req ); err != nil {
return nil , err
}
authResults := s . authResult ( ctx , req . GetId (), action . Read )
if authResults . Error != nil {
return nil , authResults . Error
}
cs , err := s . getFromRepo ( ctx , req . GetId ())
if err != nil {
return nil , err
}
outputFields , ok := requests . OutputFields ( ctx )
if ! ok {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . Internal , op , "no request context found" )
2021-06-22 22:26:26 -04:00
}
outputOpts := make ([] handlers . Option , 0 , 3 )
2023-01-06 17:27:19 -06:00
outputOpts = append ( outputOpts , handlers . WithOutputFields ( outputFields ))
2021-06-22 22:26:26 -04:00
if outputFields . Has ( globals . ScopeField ) {
outputOpts = append ( outputOpts , handlers . WithScope ( authResults . Scope ))
}
if outputFields . Has ( globals . AuthorizedActionsField ) {
outputOpts = append ( outputOpts , handlers . WithAuthorizedActions ( authResults . FetchActionSetForId ( ctx , cs . GetPublicId (), IdActions ). Strings ()))
}
if outputFields . Has ( globals . AuthorizedCollectionActionsField ) {
2022-05-18 20:20:45 -07:00
collectionActions , err := calculateAuthorizedCollectionActions ( ctx , authResults , cs . GetPublicId ())
2021-06-22 22:26:26 -04:00
if err != nil {
return nil , err
}
outputOpts = append ( outputOpts , handlers . WithAuthorizedCollectionActions ( collectionActions ))
}
2022-08-25 14:37:22 -04:00
item , err := toProto ( ctx , cs , outputOpts ... )
2021-06-22 22:26:26 -04:00
if err != nil {
return nil , err
}
return & pbs . GetCredentialStoreResponse { Item : item }, nil
}
// CreateCredentialStore implements the interface pbs.CredentialStoreServiceServer.
func ( s Service ) CreateCredentialStore ( ctx context . Context , req * pbs . CreateCredentialStoreRequest ) ( * pbs . CreateCredentialStoreResponse , error ) {
const op = "credentialstores.(Service).CreateCredentialStore"
2022-08-25 14:37:22 -04:00
if err := validateCreateRequest ( ctx , req ); err != nil {
2021-06-22 22:26:26 -04:00
return nil , err
}
authResults := s . authResult ( ctx , req . GetItem (). GetScopeId (), action . Create )
if authResults . Error != nil {
return nil , authResults . Error
}
cs , err := s . createInRepo ( ctx , authResults . Scope . GetId (), req . GetItem ())
if err != nil {
return nil , err
}
outputFields , ok := requests . OutputFields ( ctx )
if ! ok {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . Internal , op , "no request context found" )
2021-06-22 22:26:26 -04:00
}
outputOpts := make ([] handlers . Option , 0 , 3 )
2023-01-06 17:27:19 -06:00
outputOpts = append ( outputOpts , handlers . WithOutputFields ( outputFields ))
2021-06-22 22:26:26 -04:00
if outputFields . Has ( globals . ScopeField ) {
outputOpts = append ( outputOpts , handlers . WithScope ( authResults . Scope ))
}
if outputFields . Has ( globals . AuthorizedActionsField ) {
outputOpts = append ( outputOpts , handlers . WithAuthorizedActions ( authResults . FetchActionSetForId ( ctx , cs . GetPublicId (), IdActions ). Strings ()))
}
if outputFields . Has ( globals . AuthorizedCollectionActionsField ) {
2022-05-18 20:20:45 -07:00
collectionActions , err := calculateAuthorizedCollectionActions ( ctx , authResults , cs . GetPublicId ())
2021-06-22 22:26:26 -04:00
if err != nil {
return nil , err
}
outputOpts = append ( outputOpts , handlers . WithAuthorizedCollectionActions ( collectionActions ))
}
2022-08-25 14:37:22 -04:00
item , err := toProto ( ctx , cs , outputOpts ... )
2021-06-22 22:26:26 -04:00
if err != nil {
return nil , err
}
return & pbs . CreateCredentialStoreResponse {
Item : item ,
Uri : fmt . Sprintf ( "credential-stores/%s" , item . GetId ()),
}, nil
}
// UpdateCredentialStore implements the interface pbs.CredentialStoreServiceServer.
func ( s Service ) UpdateCredentialStore ( ctx context . Context , req * pbs . UpdateCredentialStoreRequest ) ( * pbs . UpdateCredentialStoreResponse , error ) {
const op = "credentialstores.(Service).UpdateCredentialStore"
2022-08-25 14:37:22 -04:00
if err := validateUpdateRequest ( ctx , req ); err != nil {
2021-06-22 22:26:26 -04:00
return nil , err
}
authResults := s . authResult ( ctx , req . GetId (), action . Update )
if authResults . Error != nil {
return nil , authResults . Error
}
cs , err := s . updateInRepo ( ctx , authResults . Scope . GetId (), req . GetId (), req . GetUpdateMask (). GetPaths (), req . GetItem ())
if err != nil {
return nil , err
}
outputFields , ok := requests . OutputFields ( ctx )
if ! ok {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . Internal , op , "no request context found" )
2021-06-22 22:26:26 -04:00
}
outputOpts := make ([] handlers . Option , 0 , 3 )
2023-01-06 17:27:19 -06:00
outputOpts = append ( outputOpts , handlers . WithOutputFields ( outputFields ))
2021-06-22 22:26:26 -04:00
if outputFields . Has ( globals . ScopeField ) {
outputOpts = append ( outputOpts , handlers . WithScope ( authResults . Scope ))
}
if outputFields . Has ( globals . AuthorizedActionsField ) {
outputOpts = append ( outputOpts , handlers . WithAuthorizedActions ( authResults . FetchActionSetForId ( ctx , cs . GetPublicId (), IdActions ). Strings ()))
}
if outputFields . Has ( globals . AuthorizedCollectionActionsField ) {
2022-05-18 20:20:45 -07:00
collectionActions , err := calculateAuthorizedCollectionActions ( ctx , authResults , cs . GetPublicId ())
2021-06-22 22:26:26 -04:00
if err != nil {
return nil , err
}
outputOpts = append ( outputOpts , handlers . WithAuthorizedCollectionActions ( collectionActions ))
}
2022-08-25 14:37:22 -04:00
item , err := toProto ( ctx , cs , outputOpts ... )
2021-06-22 22:26:26 -04:00
if err != nil {
return nil , err
}
return & pbs . UpdateCredentialStoreResponse { Item : item }, nil
}
// DeleteCredentialStore implements the interface pbs.CredentialStoreServiceServer.
func ( s Service ) DeleteCredentialStore ( ctx context . Context , req * pbs . DeleteCredentialStoreRequest ) ( * pbs . DeleteCredentialStoreResponse , error ) {
if err := validateDeleteRequest ( req ); err != nil {
return nil , err
}
authResults := s . authResult ( ctx , req . GetId (), action . Delete )
if authResults . Error != nil {
return nil , authResults . Error
}
_ , err := s . deleteFromRepo ( ctx , req . GetId ())
if err != nil {
return nil , err
}
return nil , nil
}
2022-05-18 20:20:45 -07:00
func ( s Service ) getFromRepo ( ctx context . Context , id string ) ( credential . Store , error ) {
const op = "credentialstores.(Service).getFromRepo"
2023-11-15 19:55:46 -05:00
switch globals . ResourceInfoFromPrefix ( id ). Subtype {
2023-11-02 16:03:47 -04:00
case vault . Subtype :
2022-05-18 20:20:45 -07:00
repo , err := s . vaultRepoFn ()
if err != nil {
return nil , errors . Wrap ( ctx , err , op )
}
cs , err := repo . LookupCredentialStore ( ctx , id )
if err != nil && ! errors . IsNotFoundError ( err ) {
return nil , errors . Wrap ( ctx , err , op )
}
if cs != nil {
return cs , nil
}
2023-11-02 16:03:47 -04:00
case static . Subtype :
2022-05-18 20:20:45 -07:00
repo , err := s . staticRepoFn ()
if err != nil {
return nil , errors . Wrap ( ctx , err , op )
}
cs , err := repo . LookupCredentialStore ( ctx , id )
if err != nil && ! errors . IsNotFoundError ( err ) {
return nil , errors . Wrap ( ctx , err , op )
}
if cs != nil {
return cs , nil
}
}
return nil , handlers . NotFoundErrorf ( "credential store %q not found" , id )
2021-06-22 22:26:26 -04:00
}
func ( s Service ) createInRepo ( ctx context . Context , projId string , item * pb . CredentialStore ) ( credential . Store , error ) {
const op = "credentialstores.(Service).createInRepo"
2022-05-18 20:20:45 -07:00
switch item . Type {
2023-11-02 16:03:47 -04:00
case vault . Subtype . String ():
2022-08-25 14:37:22 -04:00
cs , err := toStorageVaultStore ( ctx , projId , item )
2022-05-18 20:20:45 -07:00
if err != nil {
return nil , errors . Wrap ( ctx , err , op )
}
repo , err := s . vaultRepoFn ()
if err != nil {
return nil , errors . Wrap ( ctx , err , op )
}
out , err := repo . CreateCredentialStore ( ctx , cs )
if err != nil {
return nil , errors . Wrap ( ctx , err , op , errors . WithMsg ( "unable to create credential store" ))
}
return out , nil
2023-11-02 16:03:47 -04:00
case static . Subtype . String ():
2022-08-25 14:37:22 -04:00
cs , err := toStorageStaticStore ( ctx , projId , item )
2022-05-18 20:20:45 -07:00
if err != nil {
return nil , errors . Wrap ( ctx , err , op )
}
repo , err := s . staticRepoFn ()
if err != nil {
return nil , errors . Wrap ( ctx , err , op )
}
out , err := repo . CreateCredentialStore ( ctx , cs )
if err != nil {
return nil , errors . Wrap ( ctx , err , op , errors . WithMsg ( "unable to create credential store" ))
}
return out , nil
default :
return nil , handlers . ApiErrorWithCodeAndMessage ( codes . Internal , "Unable to create credential store, unknown type." )
2021-06-22 22:26:26 -04:00
}
}
func ( s Service ) updateInRepo ( ctx context . Context , projId , id string , mask [] string , item * pb . CredentialStore ) ( credential . Store , error ) {
const op = "credentialstores.(Service).updateInRepo"
2022-05-18 20:20:45 -07:00
var out credential . Store
var rowsUpdated int
2021-06-22 22:26:26 -04:00
dbMask := maskManager . Translate ( mask )
if len ( dbMask ) == 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." })
}
2022-05-18 20:20:45 -07:00
2023-11-15 19:55:46 -05:00
switch globals . ResourceInfoFromPrefix ( id ). Subtype {
2023-11-02 16:03:47 -04:00
case vault . Subtype :
2022-08-25 14:37:22 -04:00
cs , err := toStorageVaultStore ( ctx , projId , item )
2022-05-18 20:20:45 -07:00
if err != nil {
return nil , errors . Wrap ( ctx , err , op )
}
cs . PublicId = id
repo , err := s . vaultRepoFn ()
if err != nil {
return nil , errors . Wrap ( ctx , err , op )
}
out , rowsUpdated , err = repo . UpdateCredentialStore ( ctx , cs , item . GetVersion (), dbMask )
if err != nil {
return nil , errors . Wrap ( ctx , err , op , errors . WithMsg ( "unable to update credential store" ))
}
2023-11-02 16:03:47 -04:00
case static . Subtype :
2022-08-25 14:37:22 -04:00
cs , err := toStorageStaticStore ( ctx , projId , item )
2022-05-18 20:20:45 -07:00
if err != nil {
return nil , errors . Wrap ( ctx , err , op )
}
cs . PublicId = id
repo , err := s . staticRepoFn ()
if err != nil {
return nil , errors . Wrap ( ctx , err , op )
}
out , rowsUpdated , err = repo . UpdateCredentialStore ( ctx , cs , item . GetVersion (), dbMask )
if err != nil {
return nil , errors . Wrap ( ctx , err , op , errors . WithMsg ( "unable to update credential store" ))
}
2021-06-22 22:26:26 -04:00
}
if rowsUpdated == 0 {
return nil , handlers . NotFoundErrorf ( "Credential Store %q doesn't exist or incorrect version provided." , id )
}
return out , nil
}
func ( s Service ) deleteFromRepo ( ctx context . Context , id string ) ( bool , error ) {
const op = "credentialstores.(Service).deleteFromRepo"
2022-05-18 20:20:45 -07:00
var rows int
2023-11-15 19:55:46 -05:00
switch globals . ResourceInfoFromPrefix ( id ). Subtype {
2023-11-02 16:03:47 -04:00
case vault . Subtype :
2022-05-18 20:20:45 -07:00
repo , err := s . vaultRepoFn ()
if err != nil {
return false , err
}
rows , err = repo . DeleteCredentialStore ( ctx , id )
if err != nil {
if errors . IsNotFoundError ( err ) {
return false , nil
}
return false , errors . Wrap ( ctx , err , op , errors . WithMsg ( "unable to delete credential store" ))
}
2023-11-02 16:03:47 -04:00
case static . Subtype :
2022-05-18 20:20:45 -07:00
repo , err := s . staticRepoFn ()
if err != nil {
return false , err
}
rows , err = repo . DeleteCredentialStore ( ctx , id )
if err != nil {
if errors . IsNotFoundError ( err ) {
return false , nil
}
return false , errors . Wrap ( ctx , err , op , errors . WithMsg ( "unable to delete credential store" ))
2021-06-22 22:26:26 -04:00
}
}
return rows > 0 , nil
}
func ( s Service ) authResult ( ctx context . Context , id string , a action . Type ) auth . VerifyResults {
res := auth . VerifyResults {}
iamRepo , err := s . iamRepoFn ()
if err != nil {
res . Error = err
return res
}
2022-05-18 20:20:45 -07:00
vaultRepo , err := s . vaultRepoFn ()
if err != nil {
res . Error = err
return res
}
staticRepo , err := s . staticRepoFn ()
2021-06-22 22:26:26 -04:00
if err != nil {
res . Error = err
return res
}
var parentId string
opts := [] auth . Option { auth . WithType ( resource . CredentialStore ), auth . WithAction ( a )}
switch a {
case action . List , action . Create :
parentId = id
scp , err := iamRepo . LookupScope ( ctx , parentId )
if err != nil {
res . Error = err
return res
}
if scp == nil {
res . Error = handlers . NotFoundError ()
return res
}
default :
2023-11-15 19:55:46 -05:00
switch globals . ResourceInfoFromPrefix ( id ). Subtype {
2023-11-02 16:03:47 -04:00
case vault . Subtype :
2022-05-18 20:20:45 -07:00
cs , err := vaultRepo . LookupCredentialStore ( ctx , id )
if err != nil {
res . Error = err
return res
}
if cs == nil {
res . Error = handlers . NotFoundError ()
return res
}
2022-07-20 16:24:46 -07:00
parentId = cs . GetProjectId ()
2022-05-18 20:20:45 -07:00
2023-11-02 16:03:47 -04:00
case static . Subtype :
2022-05-18 20:20:45 -07:00
var err error
cs , err := staticRepo . LookupCredentialStore ( ctx , id )
if err != nil {
res . Error = err
return res
}
if cs == nil {
res . Error = handlers . NotFoundError ()
return res
}
2022-07-20 16:24:46 -07:00
parentId = cs . GetProjectId ()
2021-06-22 22:26:26 -04:00
}
opts = append ( opts , auth . WithId ( id ))
}
opts = append ( opts , auth . WithScopeId ( parentId ))
return auth . Verify ( ctx , opts ... )
}
2023-12-06 09:45:44 -08:00
func newOutputOpts (
ctx context . Context ,
item credential . Store ,
authResults auth . VerifyResults ,
authzScopes map [ string ] * scopes . ScopeInfo ,
) ([] handlers . Option , bool , error ) {
res := perms . Resource {
2025-01-24 10:23:33 -08:00
Type : resource . CredentialStore ,
Id : item . GetPublicId (),
ScopeId : item . GetProjectId (),
ParentScopeId : authzScopes [ item . GetProjectId ()]. GetParentScopeId (),
2023-12-06 09:45:44 -08:00
}
authorizedActions := authResults . FetchActionSetForId ( ctx , item . GetPublicId (), IdActions , auth . WithResource ( & res )). Strings ()
if len ( authorizedActions ) == 0 {
return nil , false , nil
}
outputFields := authResults . FetchOutputFields ( res , action . List ). SelfOrDefaults ( authResults . UserId )
outputOpts := make ([] handlers . Option , 0 , 3 )
outputOpts = append ( outputOpts , handlers . WithOutputFields ( outputFields ))
if outputFields . Has ( globals . ScopeField ) {
outputOpts = append ( outputOpts , handlers . WithScope ( authzScopes [ item . GetProjectId ()]))
}
if outputFields . Has ( globals . AuthorizedActionsField ) {
outputOpts = append ( outputOpts , handlers . WithAuthorizedActions ( authorizedActions ))
}
if outputFields . Has ( globals . AuthorizedCollectionActionsField ) {
collectionActions , err := calculateAuthorizedCollectionActions ( ctx , authResults , item . GetPublicId ())
if err != nil {
return nil , false , err
}
outputOpts = append ( outputOpts , handlers . WithAuthorizedCollectionActions ( collectionActions ))
}
return outputOpts , true , nil
}
2022-08-25 14:37:22 -04:00
func toProto ( ctx context . Context , in credential . Store , opt ... handlers . Option ) ( * pb . CredentialStore , error ) {
2021-06-22 22:26:26 -04:00
const op = "credentialstores.toProto"
opts := handlers . GetOpts ( opt ... )
if opts . WithOutputFields == nil {
return nil , handlers . ApiErrorWithCodeAndMessage ( codes . Internal , "output fields not found when building credential store proto" )
}
outputFields := * opts . WithOutputFields
out := pb . CredentialStore {}
if outputFields . Has ( globals . IdField ) {
out . Id = in . GetPublicId ()
}
if outputFields . Has ( globals . ScopeIdField ) {
2022-07-20 16:24:46 -07:00
out . ScopeId = in . GetProjectId ()
2021-06-22 22:26:26 -04:00
}
if outputFields . Has ( globals . TypeField ) {
2023-11-15 19:55:46 -05:00
out . Type = globals . ResourceInfoFromPrefix ( in . GetPublicId ()). Subtype . String ()
2021-06-22 22:26:26 -04:00
}
if outputFields . Has ( globals . DescriptionField ) && in . GetDescription () != "" {
out . Description = wrapperspb . String ( in . GetDescription ())
}
if outputFields . Has ( globals . NameField ) && in . GetName () != "" {
out . Name = wrapperspb . String ( in . GetName ())
}
if outputFields . Has ( globals . CreatedTimeField ) {
out . CreatedTime = in . GetCreateTime (). GetTimestamp ()
}
if outputFields . Has ( globals . UpdatedTimeField ) {
out . UpdatedTime = in . GetUpdateTime (). GetTimestamp ()
}
if outputFields . Has ( globals . VersionField ) {
out . Version = in . GetVersion ()
}
if outputFields . Has ( globals . ScopeField ) {
out . Scope = opts . WithScope
}
if outputFields . Has ( globals . AuthorizedActionsField ) {
out . AuthorizedActions = opts . WithAuthorizedActions
}
2021-09-15 13:51:15 -04:00
if outputFields . Has ( globals . AuthorizedCollectionActionsField ) {
out . AuthorizedCollectionActions = opts . WithAuthorizedCollectionActions
}
2021-06-22 22:26:26 -04:00
if outputFields . Has ( globals . AttributesField ) {
2023-11-15 19:55:46 -05:00
switch globals . ResourceInfoFromPrefix ( in . GetPublicId ()). Subtype {
2023-11-02 16:03:47 -04:00
case vault . Subtype :
2021-06-22 22:26:26 -04:00
vaultIn , ok := in .( * vault . CredentialStore )
if ! ok {
2022-08-25 14:37:22 -04:00
return nil , errors . New ( ctx , errors . Internal , op , "unable to cast to vault credential store" )
2021-06-22 22:26:26 -04:00
}
attrs := & pb . VaultCredentialStoreAttributes {
Address : wrapperspb . String ( vaultIn . GetVaultAddress ()),
}
if vaultIn . GetNamespace () != "" {
attrs . Namespace = wrapperspb . String ( vaultIn . GetNamespace ())
}
if len ( vaultIn . GetCaCert ()) != 0 {
attrs . CaCert = wrapperspb . String ( string ( vaultIn . GetCaCert ()))
}
if vaultIn . GetTlsServerName () != "" {
attrs . TlsServerName = wrapperspb . String ( vaultIn . GetTlsServerName ())
}
if vaultIn . GetTlsSkipVerify () {
attrs . TlsSkipVerify = wrapperspb . Bool ( vaultIn . GetTlsSkipVerify ())
}
if vaultIn . Token () != nil {
attrs . TokenHmac = base64 . RawURLEncoding . EncodeToString ( vaultIn . Token (). GetTokenHmac ())
2022-09-06 07:50:15 -07:00
attrs . TokenStatus = vaultIn . Token (). GetStatus ()
2021-06-22 22:26:26 -04:00
}
2022-07-22 09:13:49 -04:00
if vaultIn . GetWorkerFilter () != "" {
if vaultWorkerFilterToProto {
attrs . WorkerFilter = wrapperspb . String ( vaultIn . GetWorkerFilter ())
}
}
2021-06-22 22:26:26 -04:00
if cc := vaultIn . ClientCertificate (); cc != nil {
if len ( cc . GetCertificate ()) != 0 {
attrs . ClientCertificate = wrapperspb . String ( string ( cc . GetCertificate ()))
}
attrs . ClientCertificateKeyHmac = base64 . RawURLEncoding . EncodeToString ( cc . GetCertificateKeyHmac ())
}
2022-04-07 13:31:04 -04:00
out . Attrs = & pb . CredentialStore_VaultCredentialStoreAttributes {
VaultCredentialStoreAttributes : attrs ,
2021-06-22 22:26:26 -04:00
}
}
}
return & out , nil
}
2022-08-25 14:37:22 -04:00
func toStorageStaticStore ( ctx context . Context , scopeId string , in * pb . CredentialStore ) ( out * static . CredentialStore , err error ) {
2022-05-18 20:20:45 -07:00
const op = "credentialstores.toStorageStaticStore"
var opts [] static . Option
if in . GetName () != nil {
opts = append ( opts , static . WithName ( in . GetName (). GetValue ()))
}
if in . GetDescription () != nil {
opts = append ( opts , static . WithDescription ( in . GetDescription (). GetValue ()))
}
cs , err := static . NewCredentialStore ( scopeId , opts ... )
if err != nil {
2022-08-25 14:37:22 -04:00
return nil , errors . Wrap ( ctx , err , op , errors . WithMsg ( "unable to build credential store for creation" ))
2022-05-18 20:20:45 -07:00
}
return cs , err
}
2022-08-25 14:37:22 -04:00
func toStorageVaultStore ( ctx context . Context , scopeId string , in * pb . CredentialStore ) ( out * vault . CredentialStore , err error ) {
2021-06-22 22:26:26 -04:00
const op = "credentialstores.toStorageVaultStore"
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 ()))
}
2022-04-07 13:31:04 -04:00
attrs := in . GetVaultCredentialStoreAttributes ()
2021-06-22 22:26:26 -04:00
if attrs . GetTlsServerName () != nil {
opts = append ( opts , vault . WithTlsServerName ( attrs . GetTlsServerName (). GetValue ()))
}
if attrs . GetTlsSkipVerify (). GetValue () {
opts = append ( opts , vault . WithTlsSkipVerify ( attrs . GetTlsSkipVerify (). GetValue ()))
}
if attrs . GetNamespace (). GetValue () != "" {
opts = append ( opts , vault . WithNamespace ( attrs . GetNamespace (). GetValue ()))
}
2022-07-22 09:13:49 -04:00
if attrs . GetWorkerFilter (). GetValue () != "" {
opts = append ( opts , vault . WithWorkerFilter ( attrs . GetWorkerFilter (). GetValue ()))
}
2021-06-22 22:26:26 -04:00
// TODO (ICU-1478 and ICU-1479): Update the vault's interface around ca cert to match oidc's,
// accepting x509.Certificate instead of []byte
if attrs . GetCaCert () != nil {
opts = append ( opts , vault . WithCACert ([] byte ( attrs . GetCaCert (). GetValue ())))
}
2022-08-25 14:37:22 -04:00
pemCerts , pemPk , err := extractClientCertAndPk ( ctx , attrs . GetClientCertificate (). GetValue (), attrs . GetClientCertificateKey (). GetValue ())
2021-06-22 22:26:26 -04:00
if err != nil {
2022-08-25 14:37:22 -04:00
return nil , errors . Wrap ( ctx , err , op )
2021-06-22 22:26:26 -04:00
}
if len ( pemCerts ) != 0 {
var cert [] byte
for _ , c := range pemCerts {
cert = append ( cert , pem . EncodeToMemory ( c ) ... )
}
var pk [] byte
if pemPk != nil {
pk = pem . EncodeToMemory ( pemPk )
}
2023-06-06 17:09:08 -04:00
cc , err := vault . NewClientCertificate ( ctx , cert , pk )
2021-06-22 22:26:26 -04:00
if err != nil {
2022-08-25 14:37:22 -04:00
return nil , errors . Wrap ( ctx , err , op )
2021-06-22 22:26:26 -04:00
}
opts = append ( opts , vault . WithClientCert ( cc ))
}
cs , err := vault . NewCredentialStore ( scopeId , attrs . GetAddress (). GetValue (), [] byte ( attrs . GetToken (). GetValue ()), opts ... )
if err != nil {
2022-08-25 14:37:22 -04:00
return nil , errors . Wrap ( ctx , err , op , errors . WithMsg ( "unable to build credential store for creation" ))
2021-06-22 22:26:26 -04:00
}
return cs , err
}
// 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:
2022-08-25 09:12:24 -07:00
// - The path passed in is correctly formatted
// - All required parameters are set
// - There are no conflicting parameters provided
2021-06-22 22:26:26 -04:00
func validateGetRequest ( req * pbs . GetCredentialStoreRequest ) error {
2023-03-10 15:06:39 -05:00
return handlers . ValidateGetRequest ( handlers . NoopValidatorFn , req , globals . VaultCredentialStorePrefix , globals . StaticCredentialStorePrefix , globals . StaticCredentialStorePreviousPrefix )
2021-06-22 22:26:26 -04:00
}
2022-08-25 14:37:22 -04:00
func validateCreateRequest ( ctx context . Context , req * pbs . CreateCredentialStoreRequest ) error {
2021-06-22 22:26:26 -04:00
return handlers . ValidateCreateRequest ( req . GetItem (), func () map [ string ] string {
badFields := map [ string ] string {}
if ! handlers . ValidId ( handlers . Id ( req . GetItem (). GetScopeId ()), scope . Project . Prefix ()) {
badFields [ "scope_id" ] = "This field must be a valid project scope id."
}
2023-11-15 19:55:46 -05:00
switch req . GetItem (). GetType () {
case vault . Subtype . String ():
2022-04-07 13:31:04 -04:00
attrs := req . GetItem (). GetVaultCredentialStoreAttributes ()
if attrs == nil {
badFields [ globals . AttributesField ] = "Attributes are required for creating a vault credential store"
2021-06-22 22:26:26 -04:00
}
2022-04-07 13:31:04 -04:00
2021-06-22 22:26:26 -04:00
if attrs . GetAddress (). GetValue () == "" {
2023-01-26 10:35:29 -08:00
badFields [ globals . AttributesAddressField ] = "Field required for creating a vault credential store."
2021-06-22 22:26:26 -04:00
}
if attrs . GetToken (). GetValue () == "" {
badFields [ vaultTokenField ] = "Field required for creating a vault credential store."
}
if attrs . GetTokenHmac () != "" {
badFields [ vaultTokenHmacField ] = "This is a read only field."
}
2023-12-06 09:45:44 -08:00
if attrs . GetWorkerFilter (). GetValue () != "" {
2022-07-22 09:13:49 -04:00
err := validateVaultWorkerFilterFn ( attrs . WorkerFilter . GetValue ())
if err != nil {
badFields [ vaultWorkerFilterField ] = err . Error ()
}
}
2021-06-22 22:26:26 -04:00
// TODO(ICU-1478 and ICU-1479): Validate client and CA certificate payloads
2022-08-25 14:37:22 -04:00
_ , err := decodePemBlocks ( ctx , attrs . GetCaCert (). GetValue ())
2021-06-22 22:26:26 -04:00
if attrs . GetCaCert () != nil && err != nil {
badFields [ caCertsField ] = "Incorrectly formatted value."
}
2022-08-25 14:37:22 -04:00
cs , pk , err := extractClientCertAndPk ( ctx , attrs . GetClientCertificate (). GetValue (), attrs . GetClientCertificateKey (). GetValue ())
2021-06-22 22:26:26 -04:00
if err != nil {
badFields [ clientCertField ] = fmt . Sprintf ( "Invalid values: %q" , err . Error ())
}
if attrs . GetClientCertificate () == nil && attrs . GetClientCertificateKey () != nil {
badFields [ clientCertKeyField ] = "Cannot set a client certificate private key without the client certificate."
}
if len ( cs ) > 0 && pk == nil {
badFields [ clientCertField ] = "Cannot set a client certificate without a private key."
}
2023-11-15 19:55:46 -05:00
case static . Subtype . String ():
2022-05-18 20:20:45 -07:00
// No additional validation required for static credential store
2021-06-22 22:26:26 -04:00
default :
badFields [ globals . TypeField ] = "This is a required field and must be a known credential store type."
}
return badFields
})
}
2022-08-25 14:37:22 -04:00
func validateUpdateRequest ( ctx context . Context , req * pbs . UpdateCredentialStoreRequest ) error {
2021-06-22 22:26:26 -04:00
return handlers . ValidateUpdateRequest ( req , req . GetItem (), func () map [ string ] string {
badFields := map [ string ] string {}
2023-11-15 19:55:46 -05:00
switch globals . ResourceInfoFromPrefix ( req . GetId ()). Subtype {
2023-11-02 16:03:47 -04:00
case vault . Subtype :
2023-11-15 19:55:46 -05:00
if req . GetItem (). GetType () != "" && req . GetItem (). GetType () != vault . Subtype . String () {
2021-06-22 22:26:26 -04:00
badFields [ "type" ] = "Cannot modify resource type."
}
2022-04-07 13:31:04 -04:00
attrs := req . GetItem (). GetVaultCredentialStoreAttributes ()
if attrs != nil {
2023-01-26 10:35:29 -08:00
if handlers . MaskContains ( req . GetUpdateMask (). GetPaths (), globals . AttributesAddressField ) &&
2022-04-07 13:31:04 -04:00
attrs . GetAddress (). GetValue () == "" {
2023-01-26 10:35:29 -08:00
badFields [ globals . AttributesAddressField ] = "This is a required field and cannot be unset."
2022-04-07 13:31:04 -04:00
}
if handlers . MaskContains ( req . GetUpdateMask (). GetPaths (), vaultTokenField ) &&
attrs . GetToken (). GetValue () == "" {
badFields [ vaultTokenField ] = "This is a required field and cannot be unset."
}
if attrs . GetTokenHmac () != "" {
badFields [ vaultTokenHmacField ] = "This is a read only field."
}
2022-07-22 09:13:49 -04:00
if attrs . WorkerFilter . GetValue () != "" {
err := validateVaultWorkerFilterFn ( attrs . WorkerFilter . GetValue ())
if err != nil {
badFields [ vaultWorkerFilterField ] = err . Error ()
}
}
2021-06-22 22:26:26 -04:00
2022-04-07 13:31:04 -04:00
// TODO(ICU-1478 and ICU-1479): Validate client and CA certificate payloads
2022-08-25 14:37:22 -04:00
_ , err := decodePemBlocks ( ctx , attrs . GetCaCert (). GetValue ())
2022-04-07 13:31:04 -04:00
if attrs . GetCaCert () != nil && err != nil {
badFields [ caCertsField ] = "Incorrectly formatted value."
}
2021-06-22 22:26:26 -04:00
2022-08-25 14:37:22 -04:00
_ , _ , err = extractClientCertAndPk ( ctx , attrs . GetClientCertificate (). GetValue (), attrs . GetClientCertificateKey (). GetValue ())
2022-04-07 13:31:04 -04:00
if err != nil {
badFields [ clientCertField ] = fmt . Sprintf ( "Invalid values: %q" , err . Error ())
}
2021-06-22 22:26:26 -04:00
}
}
return badFields
2023-03-10 15:06:39 -05:00
}, globals . VaultCredentialStorePrefix , globals . StaticCredentialStorePrefix , globals . StaticCredentialStorePreviousPrefix )
2021-06-22 22:26:26 -04:00
}
func validateDeleteRequest ( req * pbs . DeleteCredentialStoreRequest ) error {
2023-03-10 15:06:39 -05:00
return handlers . ValidateDeleteRequest ( handlers . NoopValidatorFn , req , globals . VaultCredentialStorePrefix , globals . StaticCredentialStorePrefix , globals . StaticCredentialStorePreviousPrefix )
2021-06-22 22:26:26 -04:00
}
2023-06-06 17:09:08 -04:00
func validateListRequest ( ctx context . Context , req * pbs . ListCredentialStoresRequest ) error {
2021-06-22 22:26:26 -04:00
badFields := map [ string ] string {}
if ! handlers . ValidId ( handlers . Id ( req . GetScopeId ()), scope . Project . Prefix ()) &&
! req . GetRecursive () {
badFields [ globals . ScopeIdField ] = "This field must be a valid project scope ID or the list operation must be recursive."
}
2023-06-06 17:09:08 -04:00
if _ , err := handlers . NewFilter ( ctx , req . GetFilter ()); err != nil {
2021-06-22 22:26:26 -04:00
badFields [ "filter" ] = fmt . Sprintf ( "This field could not be parsed. %v" , err )
}
if len ( badFields ) > 0 {
return handlers . InvalidArgumentErrorf ( "Improperly formatted identifier." , badFields )
}
return nil
}
2022-05-18 20:20:45 -07:00
func calculateAuthorizedCollectionActions ( ctx context . Context , authResults auth . VerifyResults , id string ) ( map [ string ] * structpb . ListValue , error ) {
var collectionActions map [ string ] * structpb . ListValue
var err error
2023-11-15 19:55:46 -05:00
switch globals . ResourceInfoFromPrefix ( id ). Subtype {
2023-11-02 16:03:47 -04:00
case vault . Subtype :
2024-09-17 10:07:43 -04:00
collectionActions , err = auth . CalculateAuthorizedCollectionActions ( ctx , authResults , vaultCollectionTypeMap , authResults . Scope , id )
2022-05-18 20:20:45 -07:00
2023-11-02 16:03:47 -04:00
case static . Subtype :
2024-09-17 10:07:43 -04:00
collectionActions , err = auth . CalculateAuthorizedCollectionActions ( ctx , authResults , staticCollectionTypeMap , authResults . Scope , id )
2022-05-18 20:20:45 -07:00
}
if err != nil {
return nil , err
}
return collectionActions , nil
}