Skip to content

Commit

Permalink
Adding Response Structures to PKI Config (hashicorp#18376)
Browse files Browse the repository at this point in the history
  • Loading branch information
AnPucel committed Feb 15, 2023
1 parent 3e0487b commit d09e02a
Show file tree
Hide file tree
Showing 8 changed files with 395 additions and 7 deletions.
25 changes: 22 additions & 3 deletions builtin/logical/pki/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import (
"testing"
"time"

"github.com/hashicorp/vault/sdk/helper/testhelpers/schema"

"github.com/stretchr/testify/require"

"github.com/armon/go-metrics"
Expand Down Expand Up @@ -550,7 +552,6 @@ func generateURLSteps(t *testing.T, caCert, caKey string, intdata, reqdata map[s
if err != nil {
return err
}

if !reflect.DeepEqual(entries, expected) {
return fmt.Errorf("expected urls\n%#v\ndoes not match provided\n%#v\n", expected, entries)
}
Expand Down Expand Up @@ -1983,6 +1984,7 @@ func TestBackend_PathFetchCertList(t *testing.T) {
Data: rootData,
MountPoint: "pki/",
})

if resp != nil && resp.IsError() {
t.Fatalf("failed to generate root, %#v", resp)
}
Expand All @@ -2003,6 +2005,16 @@ func TestBackend_PathFetchCertList(t *testing.T) {
Data: urlsData,
MountPoint: "pki/",
})
schema.ValidateResponse(t, schema.GetResponseSchema(t, b.Route("config/urls"), logical.UpdateOperation), resp, true)

resp, err = b.HandleRequest(context.Background(), &logical.Request{
Operation: logical.ReadOperation,
Path: "config/urls",
Storage: storage,
MountPoint: "pki/",
})
schema.ValidateResponse(t, schema.GetResponseSchema(t, b.Route("config/urls"), logical.ReadOperation), resp, true)

if resp != nil && resp.IsError() {
t.Fatalf("failed to config urls, %#v", resp)
}
Expand Down Expand Up @@ -2410,6 +2422,8 @@ func TestBackend_Root_Idempotency(t *testing.T) {
resp, err = CBWrite(b, s, "config/ca", map[string]interface{}{
"pem_bundle": pemBundleRootCA,
})
schema.ValidateResponse(t, schema.GetResponseSchema(t, b.Route("config/ca"), logical.UpdateOperation), resp, true)

require.NoError(t, err)
require.NotNil(t, resp, "expected ca info")
firstImportedKeys := resp.Data["imported_keys"].([]string)
Expand Down Expand Up @@ -6013,11 +6027,16 @@ func TestPKI_TemplatedAIAs(t *testing.T) {
b, s := CreateBackendWithStorage(t)

// Setting templated AIAs should succeed.
_, err := CBWrite(b, s, "config/cluster", map[string]interface{}{
resp, err := CBWrite(b, s, "config/cluster", map[string]interface{}{
"path": "http://localhost:8200/v1/pki",
"aia_path": "http://localhost:8200/cdn/pki",
})
require.NoError(t, err)
schema.ValidateResponse(t, schema.GetResponseSchema(t, b.Route("config/cluster"), logical.UpdateOperation), resp, true)

resp, err = CBRead(b, s, "config/cluster")
require.NoError(t, err)
schema.ValidateResponse(t, schema.GetResponseSchema(t, b.Route("config/cluster"), logical.ReadOperation), resp, true)

aiaData := map[string]interface{}{
"crl_distribution_points": "{{cluster_path}}/issuer/{{issuer_id}}/crl/der",
Expand Down Expand Up @@ -6046,7 +6065,7 @@ func TestPKI_TemplatedAIAs(t *testing.T) {
"enable_templating": false,
})
require.NoError(t, err)
resp, err := CBWrite(b, s, "root/generate/internal", rootData)
resp, err = CBWrite(b, s, "root/generate/internal", rootData)
requireSuccessNonNilResponse(t, resp, err)
issuerId := string(resp.Data["issuer_id"].(issuerID))

Expand Down
5 changes: 5 additions & 0 deletions builtin/logical/pki/crl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"testing"
"time"

"github.com/hashicorp/vault/sdk/helper/testhelpers/schema"

"github.com/hashicorp/vault/api"
vaulthttp "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/sdk/logical"
Expand Down Expand Up @@ -90,8 +92,11 @@ func TestBackend_CRLConfig(t *testing.T) {
"auto_rebuild_grace_period": tc.autoRebuildGracePeriod,
})
requireSuccessNonNilResponse(t, resp, err)
schema.ValidateResponse(t, schema.GetResponseSchema(t, b.Route("config/crl"), logical.UpdateOperation), resp, true)

resp, err = CBRead(b, s, "config/crl")
schema.ValidateResponse(t, schema.GetResponseSchema(t, b.Route("config/crl"), logical.ReadOperation), resp, true)

requireSuccessNonNilResponse(t, resp, err)
requireFieldsSetInResp(t, resp, "disable", "expiry", "ocsp_disable", "auto_rebuild", "auto_rebuild_grace_period")

Expand Down
8 changes: 7 additions & 1 deletion builtin/logical/pki/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"fmt"
"testing"

"github.com/hashicorp/vault/sdk/helper/testhelpers/schema"

"github.com/hashicorp/vault/sdk/logical"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -371,6 +373,7 @@ func TestIntegration_AutoIssuer(t *testing.T) {
"issuer_name": "root-1",
"key_type": "ec",
})

requireSuccessNonNilResponse(t, resp, err)
issuerIdOne := resp.Data["issuer_id"]
require.NotEmpty(t, issuerIdOne)
Expand All @@ -381,12 +384,15 @@ func TestIntegration_AutoIssuer(t *testing.T) {
requireSuccessNonNilResponse(t, resp, err)
require.Equal(t, issuerIdOne, resp.Data["default"])

schema.ValidateResponse(t, schema.GetResponseSchema(t, b.Route("config/issuers"), logical.ReadOperation), resp, true)

// Enable the new config option.
_, err = CBWrite(b, s, "config/issuers", map[string]interface{}{
resp, err = CBWrite(b, s, "config/issuers", map[string]interface{}{
"default": issuerIdOne,
"default_follows_latest_issuer": true,
})
require.NoError(t, err)
schema.ValidateResponse(t, schema.GetResponseSchema(t, b.Route("config/issuers"), logical.UpdateOperation), resp, true)

// Now generate the second root; it should become default.
resp, err = CBWrite(b, s, "root/generate/internal", map[string]interface{}{
Expand Down
100 changes: 97 additions & 3 deletions builtin/logical/pki/path_config_ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package pki

import (
"context"
"net/http"

"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
Expand All @@ -21,6 +22,28 @@ secret key and certificate.`,
Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{
Callback: b.pathImportIssuers,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"mapping": {
Type: framework.TypeMap,
Description: "A mapping of issuer_id to key_id for all issuers included in this request",
Required: true,
},
"imported_keys": {
Type: framework.TypeCommaStringSlice,
Description: "Net-new keys imported as a part of this request",
Required: true,
},
"imported_issuers": {
Type: framework.TypeCommaStringSlice,
Description: "Net-new issuers imported as a part of this request",
Required: true,
},
},
}},
},
// Read more about why these flags are set in backend.go.
ForwardPerformanceStandby: true,
ForwardPerformanceSecondary: true,
Expand Down Expand Up @@ -58,13 +81,44 @@ func pathConfigIssuers(b *backend) *framework.Path {
Default: false,
},
},

Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{
Callback: b.pathCAIssuersRead,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"default": {
Type: framework.TypeString,
Description: `Reference (name or identifier) to the default issuer.`,
Required: true,
},
"default_follows_latest_issuer": {
Type: framework.TypeBool,
Description: `Whether the default issuer should automatically follow the latest generated or imported issuer. Defaults to false.`,
Required: true,
},
},
}},
},
},
logical.UpdateOperation: &framework.PathOperation{
Callback: b.pathCAIssuersWrite,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"default": {
Type: framework.TypeString,
Description: `Reference (name or identifier) to the default issuer.`,
},
"default_follows_latest_issuer": {
Type: framework.TypeBool,
Description: `Whether the default issuer should automatically follow the latest generated or imported issuer. Defaults to false.`,
},
},
}},
},
// Read more about why these flags are set in backend.go.
ForwardPerformanceStandby: true,
ForwardPerformanceSecondary: true,
Expand All @@ -90,6 +144,23 @@ func pathReplaceRoot(b *backend) *framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{
Callback: b.pathCAIssuersWrite,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"default": {
Type: framework.TypeString,
Description: `Reference (name or identifier) to the default issuer.`,
Required: true,
},
"default_follows_latest_issuer": {
Type: framework.TypeBool,
Description: `Whether the default issuer should automatically follow the latest generated or imported issuer. Defaults to false.`,
Required: true,
},
},
}},
},
// Read more about why these flags are set in backend.go.
ForwardPerformanceStandby: true,
ForwardPerformanceSecondary: true,
Expand Down Expand Up @@ -208,12 +279,35 @@ func pathConfigKeys(b *backend) *framework.Path {

Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{
Callback: b.pathKeyDefaultWrite,
Callback: b.pathKeyDefaultWrite,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"default": {
Type: framework.TypeString,
Description: `Reference (name or identifier) to the default issuer.`,
Required: true,
},
},
}},
},
ForwardPerformanceStandby: true,
ForwardPerformanceSecondary: true,
},
logical.ReadOperation: &framework.PathOperation{
Callback: b.pathKeyDefaultRead,
Callback: b.pathKeyDefaultRead,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"default": {
Type: framework.TypeString,
Description: `Reference (name or identifier) to the default issuer.`,
},
},
}},
},
ForwardPerformanceStandby: false,
ForwardPerformanceSecondary: false,
},
Expand Down
62 changes: 62 additions & 0 deletions builtin/logical/pki/path_config_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package pki
import (
"context"
"fmt"
"net/http"

"github.com/asaskevich/govalidator"
"github.com/hashicorp/vault/sdk/framework"
Expand Down Expand Up @@ -41,9 +42,70 @@ For example: http://cdn.example.com/pr1/pki`,
Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{
Callback: b.pathWriteCluster,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"path": {
Type: framework.TypeString,
Description: `Canonical URI to this mount on this performance
replication cluster's external address. This is for resolving AIA URLs and
providing the {{cluster_path}} template parameter but might be used for other
purposes in the future.
This should only point back to this particular PR replica and should not ever
point to another PR cluster. It may point to any node in the PR replica,
including standby nodes, and need not always point to the active node.
For example: https://pr1.vault.example.com:8200/v1/pki`,
},
"aia_path": {
Type: framework.TypeString,
Description: `Optional URI to this mount's AIA distribution
point; may refer to an external non-Vault responder. This is for resolving AIA
URLs and providing the {{cluster_aia_path}} template parameter and will not
be used for other purposes. As such, unlike path above, this could safely
be an insecure transit mechanism (like HTTP without TLS).
For example: http://cdn.example.com/pr1/pki`,
},
},
}},
},
},
logical.ReadOperation: &framework.PathOperation{
Callback: b.pathReadCluster,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"path": {
Type: framework.TypeString,
Description: `Canonical URI to this mount on this performance
replication cluster's external address. This is for resolving AIA URLs and
providing the {{cluster_path}} template parameter but might be used for other
purposes in the future.
This should only point back to this particular PR replica and should not ever
point to another PR cluster. It may point to any node in the PR replica,
including standby nodes, and need not always point to the active node.
For example: https://pr1.vault.example.com:8200/v1/pki`,
Required: true,
},
"aia_path": {
Type: framework.TypeString,
Description: `Optional URI to this mount's AIA distribution
point; may refer to an external non-Vault responder. This is for resolving AIA
URLs and providing the {{cluster_aia_path}} template parameter and will not
be used for other purposes. As such, unlike path above, this could safely
be an insecure transit mechanism (like HTTP without TLS).
For example: http://cdn.example.com/pr1/pki`,
},
},
}},
},
},
},

Expand Down
Loading

0 comments on commit d09e02a

Please sign in to comment.