4dbbd3e1f8
This decreases the total time to run the test suite significantly. From the last PR, we were at 151s: > [cipherboy@xps15 pki]$ go test -count=1 github.com/hashicorp/vault/builtin/logical/pki > ok github.com/hashicorp/vault/builtin/logical/pki 151.182s Now we're around 60s: > [cipherboy@xps15 pki]$ go test -count=1 github.com/hashicorp/vault/builtin/logical/pki > ok github.com/hashicorp/vault/builtin/logical/pki 61.838s Notably, Go will correctly handle parallelizing tests across both packages and within a package, so this shouldn't really impact test runners (if they're already saturated). The only gotcha in this approach is that the call to t.Run(...) becomes effectively async; this means we either need to not mark the test as parallel or shadow any loop variables inside the scope of the loop to allow the t.Run to have the correct copy. Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
234 lines
5.8 KiB
Go
234 lines
5.8 KiB
Go
package pki
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/vault/sdk/framework"
|
|
"github.com/hashicorp/vault/sdk/logical"
|
|
)
|
|
|
|
func TestPki_FetchCertBySerial(t *testing.T) {
|
|
t.Parallel()
|
|
b, storage := createBackendWithStorage(t)
|
|
|
|
cases := map[string]struct {
|
|
Req *logical.Request
|
|
Prefix string
|
|
Serial string
|
|
}{
|
|
"valid cert": {
|
|
&logical.Request{
|
|
Storage: storage,
|
|
},
|
|
"certs/",
|
|
"00:00:00:00:00:00:00:00",
|
|
},
|
|
"revoked cert": {
|
|
&logical.Request{
|
|
Storage: storage,
|
|
},
|
|
"revoked/",
|
|
"11:11:11:11:11:11:11:11",
|
|
},
|
|
}
|
|
|
|
// Test for colon-based paths in storage
|
|
for name, tc := range cases {
|
|
storageKey := fmt.Sprintf("%s%s", tc.Prefix, tc.Serial)
|
|
err := storage.Put(context.Background(), &logical.StorageEntry{
|
|
Key: storageKey,
|
|
Value: []byte("some data"),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("error writing to storage on %s colon-based storage path: %s", name, err)
|
|
}
|
|
|
|
certEntry, err := fetchCertBySerial(context.Background(), b, tc.Req, tc.Prefix, tc.Serial)
|
|
if err != nil {
|
|
t.Fatalf("error on %s for colon-based storage path: %s", name, err)
|
|
}
|
|
|
|
// Check for non-nil on valid/revoked certs
|
|
if certEntry == nil {
|
|
t.Fatalf("nil on %s for colon-based storage path", name)
|
|
}
|
|
|
|
// Ensure that cert serials are converted/updated after fetch
|
|
expectedKey := tc.Prefix + normalizeSerial(tc.Serial)
|
|
se, err := storage.Get(context.Background(), expectedKey)
|
|
if err != nil {
|
|
t.Fatalf("error on %s for colon-based storage path:%s", name, err)
|
|
}
|
|
if strings.Compare(expectedKey, se.Key) != 0 {
|
|
t.Fatalf("expected: %s, got: %s", expectedKey, certEntry.Key)
|
|
}
|
|
}
|
|
|
|
// Reset storage
|
|
storage = &logical.InmemStorage{}
|
|
|
|
// Test for hyphen-base paths in storage
|
|
for name, tc := range cases {
|
|
storageKey := tc.Prefix + normalizeSerial(tc.Serial)
|
|
err := storage.Put(context.Background(), &logical.StorageEntry{
|
|
Key: storageKey,
|
|
Value: []byte("some data"),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("error writing to storage on %s hyphen-based storage path: %s", name, err)
|
|
}
|
|
|
|
certEntry, err := fetchCertBySerial(context.Background(), b, tc.Req, tc.Prefix, tc.Serial)
|
|
if err != nil || certEntry == nil {
|
|
t.Fatalf("error on %s for hyphen-based storage path: err: %v, entry: %v", name, err, certEntry)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Demonstrate that multiple OUs in the name are handled in an
|
|
// order-preserving way.
|
|
func TestPki_MultipleOUs(t *testing.T) {
|
|
t.Parallel()
|
|
var b backend
|
|
fields := addCACommonFields(map[string]*framework.FieldSchema{})
|
|
|
|
apiData := &framework.FieldData{
|
|
Schema: fields,
|
|
Raw: map[string]interface{}{
|
|
"cn": "example.com",
|
|
"ttl": 3600,
|
|
},
|
|
}
|
|
input := &inputBundle{
|
|
apiData: apiData,
|
|
role: &roleEntry{
|
|
MaxTTL: 3600,
|
|
OU: []string{"Z", "E", "V"},
|
|
},
|
|
}
|
|
cb, err := generateCreationBundle(&b, input, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("Error: %v", err)
|
|
}
|
|
|
|
expected := []string{"Z", "E", "V"}
|
|
actual := cb.Params.Subject.OrganizationalUnit
|
|
|
|
if !reflect.DeepEqual(expected, actual) {
|
|
t.Fatalf("Expected %v, got %v", expected, actual)
|
|
}
|
|
}
|
|
|
|
func TestPki_PermitFQDNs(t *testing.T) {
|
|
t.Parallel()
|
|
var b backend
|
|
fields := addCACommonFields(map[string]*framework.FieldSchema{})
|
|
|
|
cases := map[string]struct {
|
|
input *inputBundle
|
|
expectedDnsNames []string
|
|
expectedEmails []string
|
|
}{
|
|
"base valid case": {
|
|
input: &inputBundle{
|
|
apiData: &framework.FieldData{
|
|
Schema: fields,
|
|
Raw: map[string]interface{}{
|
|
"common_name": "example.com.",
|
|
"ttl": 3600,
|
|
},
|
|
},
|
|
role: &roleEntry{
|
|
AllowAnyName: true,
|
|
MaxTTL: 3600,
|
|
EnforceHostnames: true,
|
|
},
|
|
},
|
|
expectedDnsNames: []string{"example.com."},
|
|
expectedEmails: []string{},
|
|
},
|
|
"case insensitivity validation": {
|
|
input: &inputBundle{
|
|
apiData: &framework.FieldData{
|
|
Schema: fields,
|
|
Raw: map[string]interface{}{
|
|
"common_name": "Example.Net",
|
|
"alt_names": "eXaMPLe.COM",
|
|
"ttl": 3600,
|
|
},
|
|
},
|
|
role: &roleEntry{
|
|
AllowedDomains: []string{"example.net", "EXAMPLE.COM"},
|
|
AllowBareDomains: true,
|
|
MaxTTL: 3600,
|
|
},
|
|
},
|
|
expectedDnsNames: []string{"Example.Net", "eXaMPLe.COM"},
|
|
expectedEmails: []string{},
|
|
},
|
|
"case email as AllowedDomain with bare domains": {
|
|
input: &inputBundle{
|
|
apiData: &framework.FieldData{
|
|
Schema: fields,
|
|
Raw: map[string]interface{}{
|
|
"common_name": "test@testemail.com",
|
|
"ttl": 3600,
|
|
},
|
|
},
|
|
role: &roleEntry{
|
|
AllowedDomains: []string{"test@testemail.com"},
|
|
AllowBareDomains: true,
|
|
MaxTTL: 3600,
|
|
},
|
|
},
|
|
expectedDnsNames: []string{},
|
|
expectedEmails: []string{"test@testemail.com"},
|
|
},
|
|
"case email common name with bare domains": {
|
|
input: &inputBundle{
|
|
apiData: &framework.FieldData{
|
|
Schema: fields,
|
|
Raw: map[string]interface{}{
|
|
"common_name": "test@testemail.com",
|
|
"ttl": 3600,
|
|
},
|
|
},
|
|
role: &roleEntry{
|
|
AllowedDomains: []string{"testemail.com"},
|
|
AllowBareDomains: true,
|
|
MaxTTL: 3600,
|
|
},
|
|
},
|
|
expectedDnsNames: []string{},
|
|
expectedEmails: []string{"test@testemail.com"},
|
|
},
|
|
}
|
|
|
|
for name, testCase := range cases {
|
|
name := name
|
|
testCase := testCase
|
|
t.Run(name, func(t *testing.T) {
|
|
cb, err := generateCreationBundle(&b, testCase.input, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("Error: %v", err)
|
|
}
|
|
|
|
actualDnsNames := cb.Params.DNSNames
|
|
|
|
if !reflect.DeepEqual(testCase.expectedDnsNames, actualDnsNames) {
|
|
t.Fatalf("Expected dns names %v, got %v", testCase.expectedDnsNames, actualDnsNames)
|
|
}
|
|
|
|
actualEmails := cb.Params.EmailAddresses
|
|
|
|
if !reflect.DeepEqual(testCase.expectedEmails, actualEmails) {
|
|
t.Fatalf("Expected email addresses %v, got %v", testCase.expectedEmails, actualEmails)
|
|
}
|
|
})
|
|
}
|
|
}
|