diff --git a/changelog/12932.txt b/changelog/12932.txt new file mode 100644 index 000000000..cd2224e81 --- /dev/null +++ b/changelog/12932.txt @@ -0,0 +1,3 @@ +```release-note:feature +**OIDC Identity Provider (Tech Preview)**: Adds support for Vault to be an OpenID Connect (OIDC) provider. +``` diff --git a/vault/identity_store_oidc_provider.go b/vault/identity_store_oidc_provider.go index a24d9d6be..83600a1e6 100644 --- a/vault/identity_store_oidc_provider.go +++ b/vault/identity_store_oidc_provider.go @@ -607,6 +607,9 @@ func (i *IdentityStore) providersReferencingTargetScopeName(ctx context.Context, func (i *IdentityStore) pathOIDCCreateUpdateAssignment(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { name := d.Get("name").(string) + i.oidcLock.Lock() + defer i.oidcLock.Unlock() + var assignment assignment if req.Operation == logical.UpdateOperation { entry, err := req.Storage.Get(ctx, assignmentPath+name) @@ -699,6 +702,9 @@ func (i *IdentityStore) getOIDCAssignment(ctx context.Context, s logical.Storage func (i *IdentityStore) pathOIDCDeleteAssignment(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { name := d.Get("name").(string) + i.oidcLock.Lock() + defer i.oidcLock.Unlock() + clientNames, err := i.clientNamesReferencingTargetAssignmentName(ctx, req, name) if err != nil { return nil, err @@ -735,6 +741,9 @@ func (i *IdentityStore) pathOIDCCreateUpdateScope(ctx context.Context, req *logi return logical.ErrorResponse("the %q scope name is reserved", openIDScope), nil } + i.oidcLock.Lock() + defer i.oidcLock.Unlock() + var scope scope if req.Operation == logical.UpdateOperation { entry, err := req.Storage.Get(ctx, scopePath+name) @@ -848,20 +857,21 @@ func (i *IdentityStore) getOIDCScope(ctx context.Context, s logical.Storage, nam return &scope, nil } -// pathOIDCDeleteScope is used to delete an scope +// pathOIDCDeleteScope is used to delete a scope func (i *IdentityStore) pathOIDCDeleteScope(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { name := d.Get("name").(string) - targetScopeName := d.Get("name").(string) + i.oidcLock.Lock() + defer i.oidcLock.Unlock() - providerNames, err := i.providersReferencingTargetScopeName(ctx, req, targetScopeName) + providerNames, err := i.providersReferencingTargetScopeName(ctx, req, name) if err != nil { return nil, err } if len(providerNames) > 0 { errorMessage := fmt.Sprintf("unable to delete scope %q because it is currently referenced by these providers: %s", - targetScopeName, strings.Join(providerNames, ", ")) + name, strings.Join(providerNames, ", ")) return logical.ErrorResponse(errorMessage), logical.ErrInvalidRequest } err = req.Storage.Delete(ctx, scopePath+name) @@ -892,6 +902,9 @@ func (i *IdentityStore) pathOIDCCreateUpdateClient(ctx context.Context, req *log return nil, err } + i.oidcLock.Lock() + defer i.oidcLock.Unlock() + client := client{ Name: name, NamespaceID: ns.ID, @@ -949,18 +962,14 @@ func (i *IdentityStore) pathOIDCCreateUpdateClient(ctx context.Context, req *log return logical.ErrorResponse("the key parameter is required"), nil } - var key namedKey // enforce key existence on client creation - entry, err := req.Storage.Get(ctx, namedKeyConfigPath+client.Key) + key, err := i.getNamedKey(ctx, req.Storage, client.Key) if err != nil { return nil, err } - if entry == nil { + if key == nil { return logical.ErrorResponse("key %q does not exist", client.Key), nil } - if err := entry.DecodeJSON(&key); err != nil { - return nil, err - } if idTokenTTLRaw, ok := d.GetOk("id_token_ttl"); ok { client.IDTokenTTL = time.Duration(idTokenTTLRaw.(int)) * time.Second @@ -1002,7 +1011,7 @@ func (i *IdentityStore) pathOIDCCreateUpdateClient(ctx context.Context, req *log } // store client - entry, err = logical.StorageEntryJSON(clientPath+name, client) + entry, err := logical.StorageEntryJSON(clientPath+name, client) if err != nil { return nil, err } @@ -1047,10 +1056,13 @@ func (i *IdentityStore) pathOIDCReadClient(ctx context.Context, req *logical.Req }, nil } -// pathOIDCDeleteClient is used to delete an client +// pathOIDCDeleteClient is used to delete a client func (i *IdentityStore) pathOIDCDeleteClient(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { name := d.Get("name").(string) + i.oidcLock.Lock() + defer i.oidcLock.Unlock() + // Delete the client from memdb if err := i.memDBDeleteClientByName(ctx, name); err != nil { return nil, err @@ -1080,6 +1092,9 @@ func (i *IdentityStore) pathOIDCCreateUpdateProvider(ctx context.Context, req *l var resp logical.Response name := d.Get("name").(string) + i.oidcLock.Lock() + defer i.oidcLock.Unlock() + var provider provider if req.Operation == logical.UpdateOperation { entry, err := req.Storage.Get(ctx, providerPath+name) @@ -1260,7 +1275,7 @@ func (i *IdentityStore) getOIDCProvider(ctx context.Context, s logical.Storage, return &provider, nil } -// pathOIDCDeleteProvider is used to delete an assignment +// pathOIDCDeleteProvider is used to delete a provider func (i *IdentityStore) pathOIDCDeleteProvider(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { name := d.Get("name").(string) return nil, req.Storage.Delete(ctx, providerPath+name)