mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 17:52:32 +00:00
* Adding explicit MPL license for sub-package. This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Adding explicit MPL license for sub-package. This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Updating the license from MPL to Business Source License. Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at https://hashi.co/bsl-blog, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl. * add missing license headers * Update copyright file headers to BUS-1.1 * Fix test that expected exact offset on hcl file --------- Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com> Co-authored-by: Sarah Thompson <sthompson@hashicorp.com> Co-authored-by: Brian Kassouf <bkassouf@hashicorp.com>
264 lines
7.0 KiB
Go
264 lines
7.0 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package transit
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/vault/helper/testhelpers"
|
|
"github.com/hashicorp/vault/sdk/logical"
|
|
)
|
|
|
|
func TestTransit_Restore(t *testing.T) {
|
|
// Test setup:
|
|
// - Create a key
|
|
// - Configure it to be exportable, allowing deletion, and backups
|
|
// - Capture backup
|
|
// - Delete key
|
|
// - Run test cases
|
|
//
|
|
// Each test case should start with no key present. If the 'Seed' parameter is
|
|
// in the struct, we'll start by restoring it (without force) to run that test
|
|
// as if the key already existed
|
|
|
|
keyType := "aes256-gcm96"
|
|
b, s := createBackendWithStorage(t)
|
|
keyName := testhelpers.RandomWithPrefix("my-key")
|
|
|
|
// Create a key
|
|
keyReq := &logical.Request{
|
|
Path: "keys/" + keyName,
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
Data: map[string]interface{}{
|
|
"type": keyType,
|
|
"exportable": true,
|
|
},
|
|
}
|
|
resp, err := b.HandleRequest(context.Background(), keyReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
|
|
// Configure the key to allow its deletion and backup
|
|
configReq := &logical.Request{
|
|
Path: fmt.Sprintf("keys/%s/config", keyName),
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
Data: map[string]interface{}{
|
|
"deletion_allowed": true,
|
|
"allow_plaintext_backup": true,
|
|
},
|
|
}
|
|
resp, err = b.HandleRequest(context.Background(), configReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
|
|
// Take a backup of the key
|
|
backupReq := &logical.Request{
|
|
Path: "backup/" + keyName,
|
|
Operation: logical.ReadOperation,
|
|
Storage: s,
|
|
}
|
|
resp, err = b.HandleRequest(context.Background(), backupReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
|
|
backupKey := resp.Data["backup"].(string)
|
|
if backupKey == "" {
|
|
t.Fatal("failed to get a backup")
|
|
}
|
|
|
|
// Delete the key to start test cases with clean slate
|
|
keyReq.Operation = logical.DeleteOperation
|
|
resp, err = b.HandleRequest(context.Background(), keyReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
|
|
// helper func to get a pointer value for a boolean
|
|
boolPtr := func(b bool) *bool {
|
|
return &b
|
|
}
|
|
|
|
keyExitsError := fmt.Errorf("key %q already exists", keyName)
|
|
|
|
testCases := []struct {
|
|
Name string
|
|
// Seed dermines if we start the test by restoring the initial backup we
|
|
// took, to test a restore operation based on the key existing or not
|
|
Seed bool
|
|
// Force is a pointer to differentiate between default false and given false
|
|
Force *bool
|
|
// The error we expect, if any
|
|
ExpectedErr error
|
|
|
|
// RestoreName is used to restore the key to a differnt name
|
|
RestoreName string
|
|
}{
|
|
{
|
|
// key does not already exist
|
|
Name: "Default restore",
|
|
},
|
|
{
|
|
// key already exists
|
|
Name: "Restore-without-force",
|
|
Seed: true,
|
|
ExpectedErr: keyExitsError,
|
|
},
|
|
{
|
|
// key already exists, use force to force a restore
|
|
Name: "Restore-with-force",
|
|
Seed: true,
|
|
Force: boolPtr(true),
|
|
},
|
|
{
|
|
// using force shouldn't matter if the key doesn't exist
|
|
Name: "Restore-with-force-no-seed",
|
|
Force: boolPtr(true),
|
|
},
|
|
{
|
|
// key already exists, restore to new name
|
|
Name: "Restore-new-name",
|
|
Seed: true,
|
|
RestoreName: "new-key",
|
|
},
|
|
{
|
|
// key already exists, restore to bad path, should error
|
|
Name: "Restore-new-name-bad-path",
|
|
Seed: true,
|
|
RestoreName: "sub/path/new-key",
|
|
ExpectedErr: ErrInvalidKeyName,
|
|
},
|
|
{
|
|
// using force shouldn't matter if the restore key name is different
|
|
Name: "Restore-with-force-seed-new-name",
|
|
Seed: true,
|
|
Force: boolPtr(true),
|
|
RestoreName: "other-key",
|
|
},
|
|
{
|
|
// using force shouldn't matter if the restore key name is different
|
|
Name: "Restore-with-out-force-seed-new-name",
|
|
Seed: true,
|
|
Force: boolPtr(false),
|
|
RestoreName: "other-key",
|
|
},
|
|
{
|
|
// using force shouldn't matter if the key doesn't exist
|
|
Name: "Restore-force-false",
|
|
Force: boolPtr(false),
|
|
},
|
|
{
|
|
// using false force should still error
|
|
Name: "Restore-force-false",
|
|
Seed: true,
|
|
Force: boolPtr(false),
|
|
ExpectedErr: keyExitsError,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
var resp *logical.Response
|
|
var err error
|
|
if tc.Seed {
|
|
// restore our key to test a pre-existing key
|
|
seedRestoreReq := &logical.Request{
|
|
Path: "restore",
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
Data: map[string]interface{}{
|
|
"backup": backupKey,
|
|
},
|
|
}
|
|
|
|
resp, err := b.HandleRequest(context.Background(), seedRestoreReq)
|
|
if resp != nil && resp.IsError() {
|
|
t.Fatalf("resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
if err != nil && tc.ExpectedErr == nil {
|
|
t.Fatalf("did not expect an error in SeedKey restore: %s", err)
|
|
}
|
|
}
|
|
|
|
restorePath := "restore"
|
|
if tc.RestoreName != "" {
|
|
restorePath = fmt.Sprintf("%s/%s", restorePath, tc.RestoreName)
|
|
}
|
|
|
|
restoreReq := &logical.Request{
|
|
Path: restorePath,
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
Data: map[string]interface{}{
|
|
"backup": backupKey,
|
|
},
|
|
}
|
|
|
|
if tc.Force != nil {
|
|
restoreReq.Data["force"] = *tc.Force
|
|
}
|
|
|
|
resp, err = b.HandleRequest(context.Background(), restoreReq)
|
|
if resp != nil && resp.IsError() {
|
|
t.Fatalf("resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
if err == nil && tc.ExpectedErr != nil {
|
|
t.Fatalf("expected an error, but got none")
|
|
}
|
|
if err != nil && tc.ExpectedErr == nil {
|
|
t.Fatalf("unexpected error:%s", err)
|
|
}
|
|
|
|
if err != nil && tc.ExpectedErr != nil {
|
|
if err.Error() != tc.ExpectedErr.Error() {
|
|
t.Fatalf("expected error: (%s), got: (%s)", tc.ExpectedErr.Error(), err.Error())
|
|
}
|
|
}
|
|
|
|
readKeyName := keyName
|
|
if tc.RestoreName != "" {
|
|
readKeyName = tc.RestoreName
|
|
}
|
|
|
|
// read the key and make sure it's there
|
|
readReq := &logical.Request{
|
|
Path: "keys/" + readKeyName,
|
|
Operation: logical.ReadOperation,
|
|
Storage: s,
|
|
}
|
|
|
|
resp, _ = b.HandleRequest(context.Background(), readReq)
|
|
if resp != nil && resp.IsError() {
|
|
t.Fatalf("resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
|
|
if tc.ExpectedErr == nil && resp == nil {
|
|
t.Fatal("expected to find a key, but got none")
|
|
}
|
|
|
|
// cleanup / delete key after each run
|
|
keyReq.Operation = logical.DeleteOperation
|
|
resp, err = b.HandleRequest(context.Background(), keyReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
|
|
// cleanup / delete restore key after each run, if it was created
|
|
if tc.RestoreName != "" && tc.ExpectedErr == nil {
|
|
readReq.Operation = logical.DeleteOperation
|
|
resp, err = b.HandleRequest(context.Background(), readReq)
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|