From fef9e348c61e1d3c07e5e43be12784f2a4459e5f Mon Sep 17 00:00:00 2001 From: miagilepner Date: Thu, 23 Apr 2026 17:04:12 +0200 Subject: [PATCH] VAULT-44100: Backport missing oauth changes to CE (#14222) * CE changes for agent registry/oauth * add oauth resource config server profile to ce stub --- sdk/helper/locksutil/locks.go | 9 +++++++++ vault/identity_store_aliases.go | 11 +++++++++++ vault/identity_store_aliases_stubs_oss.go | 4 ++++ vault/identity_store_structs.go | 1 + vault/request_handling.go | 4 ++-- vault/request_handling_ce.go | 8 +++++--- 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/sdk/helper/locksutil/locks.go b/sdk/helper/locksutil/locks.go index 378cd8f5f0..1897daf96c 100644 --- a/sdk/helper/locksutil/locks.go +++ b/sdk/helper/locksutil/locks.go @@ -54,10 +54,19 @@ func LockIndexForKey(key string) uint8 { return uint8(cryptoutil.Blake2b256Hash(key)[0]) } +// LockForKey returns the striped lock entry for a key. +// Different logical keys can hash to the same underlying lock, so callers must +// not assume two keys imply two distinct RWMutexes. If a code path needs to +// lock more than one key, prefer LocksForKeys to deduplicate aliased stripes and +// avoid self-deadlocking by re-entering the same lock. func LockForKey(locks []*LockEntry, key string) *LockEntry { return locks[LockIndexForKey(key)] } +// LocksForKeys returns the unique striped lock entries for a set of keys in a +// stable slice order. Use this when a code path needs more than one keyed lock: +// it deduplicates keys that alias to the same stripe and supports consistent +// acquisition ordering across callers. func LocksForKeys(locks []*LockEntry, keys []string) []*LockEntry { lockIndexes := make(map[uint8]struct{}, len(keys)) for _, k := range keys { diff --git a/vault/identity_store_aliases.go b/vault/identity_store_aliases.go index 065bbe6132..f47c54151c 100644 --- a/vault/identity_store_aliases.go +++ b/vault/identity_store_aliases.go @@ -315,6 +315,17 @@ func (i *IdentityStore) handleAliasCreateUpdate() framework.OperationFunc { } } + // If they didn't provide an ID or Mount Accessor, but provided an issuer, validate that the issuer has been + // registered. Return error if issuer has not been registered. + if mountAccessor == "" && issuer != "" { + // Generate synthetic Mount Accessor + syntheticAccessor, err := i.syntheticAliasAccessorValidator.generateSyntheticAliasAccessor(ctx, issuer) + if err != nil { + return logical.ErrorResponse(err.Error()), nil + } + mountAccessor = syntheticAccessor + } + // If they didn't provide an ID, we must have both accessor and name provided if mountAccessor == "" || name == "" { return logical.ErrorResponse("'id' or 'mount_accessor' and 'name' must be provided"), nil diff --git a/vault/identity_store_aliases_stubs_oss.go b/vault/identity_store_aliases_stubs_oss.go index 396f910aa1..122bef6485 100644 --- a/vault/identity_store_aliases_stubs_oss.go +++ b/vault/identity_store_aliases_stubs_oss.go @@ -10,3 +10,7 @@ import "context" func (c *Core) validateSyntheticAliasAccessor(context.Context, string) (bool, error) { return false, nil } + +func (c *Core) generateSyntheticAliasAccessor(context.Context, string) (string, error) { + return "", nil +} diff --git a/vault/identity_store_structs.go b/vault/identity_store_structs.go index 0e405082c9..314239deb6 100644 --- a/vault/identity_store_structs.go +++ b/vault/identity_store_structs.go @@ -199,6 +199,7 @@ var _ MountLister = &Core{} type SyntheticAliasAccessorValidator interface { validateSyntheticAliasAccessor(context.Context, string) (bool, error) + generateSyntheticAliasAccessor(context.Context, string) (string, error) } var _ SyntheticAliasAccessorValidator = &Core{} diff --git a/vault/request_handling.go b/vault/request_handling.go index d45e00e3f1..a96d5d3d68 100644 --- a/vault/request_handling.go +++ b/vault/request_handling.go @@ -242,7 +242,7 @@ func (c *Core) fetchACLTokenEntryAndEntity(ctx context.Context, req *logical.Req var secondEntity *identity.Entity if IsEnterpriseToken(req.ClientToken) { - isValidEnterpriseToken, tokenMetadataContainer, entity, actorEntity, err := c.validateEnterpriseTokenAndFetchEntity(ctx, req.ClientToken) + isValidEnterpriseToken, tokenMetadataContainer, entity, actorEntity, chosenProfile, err := c.validateEnterpriseTokenAndFetchEntity(ctx, req.ClientToken) if err != nil { c.logger.Error("failed to validate enterprise token", "error", err) } @@ -256,7 +256,7 @@ func (c *Core) fetchACLTokenEntryAndEntity(ctx context.Context, req *logical.Req _, req.EnterpriseTokenAuthorizationDetailsPresent = tokenMetadataContainer["authorization_details"] req.EnterpriseTokenAuthorizationDetails = getEnterpriseTokenAuthorizationDetails(tokenMetadataContainer) secondEntity = actorEntity - err = c.createAndStoreEnterpriseTokenEntry(ctx, req, tokenMetadataContainer, entity, actorEntity) + err = c.createAndStoreEnterpriseTokenEntry(ctx, req, tokenMetadataContainer, entity, actorEntity, chosenProfile) if err != nil { if c.perfStandby && errors.Is(err, logical.ErrReadOnly) { return nil, nil, nil, nil, logical.ErrPerfStandbyPleaseForward diff --git a/vault/request_handling_ce.go b/vault/request_handling_ce.go index c6bc5fa342..487740fa98 100644 --- a/vault/request_handling_ce.go +++ b/vault/request_handling_ce.go @@ -13,11 +13,13 @@ import ( "github.com/hashicorp/vault/sdk/logical" ) -func (c *Core) validateEnterpriseTokenAndFetchEntity(ctx context.Context, tokenString string) (bool, map[string]interface{}, *identity.Entity, *identity.Entity, error) { - return false, nil, nil, nil, errors.New("not implemented") +type OAuthResourceServerConfigProfile struct{} + +func (c *Core) validateEnterpriseTokenAndFetchEntity(ctx context.Context, tokenString string) (bool, map[string]interface{}, *identity.Entity, *identity.Entity, *OAuthResourceServerConfigProfile, error) { + return false, nil, nil, nil, nil, errors.New("not implemented") } -func (c *Core) createAndStoreEnterpriseTokenEntry(ctx context.Context, req *logical.Request, allClaims map[string]interface{}, entity *identity.Entity, actorEntity *identity.Entity) error { +func (c *Core) createAndStoreEnterpriseTokenEntry(ctx context.Context, req *logical.Request, allClaims map[string]interface{}, entity *identity.Entity, actorEntity *identity.Entity, chosenProfile *OAuthResourceServerConfigProfile) error { return nil }