open-vault/builtin/logical/pki/path_acme_nonce.go
Alexander Scheel 3ed31ff262
Add acme account storage (#19953)
* Enable creation of accounts

 - Refactors many methods to take an acmeContext, which holds the
   storageContext on it.
 - Updates the core ACME Handlers to use *acmeContext, to avoid
   copying structs.
 - Makes JWK exported so the JSON parser can find it.

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>

* Finish ACME account creation

 - This ensures a Kid is created when one doesn't exist
 - Expands the parsed handler capabilities, to format the response and
   set required headers.

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>

---------

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2023-04-03 16:08:25 -04:00

85 lines
2.5 KiB
Go

package pki
import (
"fmt"
"net/http"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
)
func pathAcmeRootNonce(b *backend) *framework.Path {
return patternAcmeNonce(b, "acme/new-nonce")
}
func pathAcmeRoleNonce(b *backend) *framework.Path {
return patternAcmeNonce(b, "roles/"+framework.GenericNameRegex("role")+"/acme/new-nonce")
}
func pathAcmeIssuerNonce(b *backend) *framework.Path {
return patternAcmeNonce(b, "issuer/"+framework.GenericNameRegex(issuerRefParam)+"/acme/new-nonce")
}
func pathAcmeIssuerAndRoleNonce(b *backend) *framework.Path {
return patternAcmeNonce(b,
"issuer/"+framework.GenericNameRegex(issuerRefParam)+
"/roles/"+framework.GenericNameRegex("role")+"/acme/new-nonce")
}
func patternAcmeNonce(b *backend, pattern string) *framework.Path {
fields := map[string]*framework.FieldSchema{}
addFieldsForACMEPath(fields, pattern)
return &framework.Path{
Pattern: pattern,
Fields: fields,
Operations: map[logical.Operation]framework.OperationHandler{
logical.HeaderOperation: &framework.PathOperation{
Callback: b.acmeWrapper(b.acmeNonceHandler),
ForwardPerformanceSecondary: false,
ForwardPerformanceStandby: true,
},
logical.ReadOperation: &framework.PathOperation{
Callback: b.acmeWrapper(b.acmeNonceHandler),
ForwardPerformanceSecondary: false,
ForwardPerformanceStandby: true,
},
},
HelpSynopsis: pathAcmeDirectoryHelpSync,
HelpDescription: pathAcmeDirectoryHelpDesc,
}
}
func (b *backend) acmeNonceHandler(ctx *acmeContext, r *logical.Request, _ *framework.FieldData) (*logical.Response, error) {
nonce, _, err := b.acmeState.GetNonce()
if err != nil {
return nil, err
}
// Header operations return 200, GET return 204.
httpStatus := http.StatusOK
if r.Operation == logical.ReadOperation {
httpStatus = http.StatusNoContent
}
return &logical.Response{
Headers: map[string][]string{
"Cache-Control": {"no-store"},
"Replay-Nonce": {nonce},
"Link": genAcmeLinkHeader(ctx),
},
Data: map[string]interface{}{
logical.HTTPStatusCode: httpStatus,
// Get around Vault limitation of requiring a body set if the status is not http.StatusNoContent
// for our HEAD request responses.
logical.HTTPContentType: "",
},
}, nil
}
func genAcmeLinkHeader(ctx *acmeContext) []string {
path := fmt.Sprintf("<%s>;rel=\"index\"", ctx.baseUrl.JoinPath("directory").String())
return []string{path}
}