mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	 fe68295256
			
		
	
	fe68295256
	
	
	
		
			
			* return 403 for wrapping requests when no token provided * add changelog entry * fix changelog * use errors.As * simplify error response string
		
			
				
	
	
		
			387 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			387 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package http
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"errors"
 | |
| 	"reflect"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/hashicorp/vault/api"
 | |
| 	"github.com/hashicorp/vault/sdk/helper/jsonutil"
 | |
| 	"github.com/hashicorp/vault/vault"
 | |
| )
 | |
| 
 | |
| // Test wrapping functionality
 | |
| func TestHTTP_Wrapping(t *testing.T) {
 | |
| 	cluster := vault.NewTestCluster(t, &vault.CoreConfig{}, &vault.TestClusterOptions{
 | |
| 		HandlerFunc: Handler,
 | |
| 	})
 | |
| 	cluster.Start()
 | |
| 	defer cluster.Cleanup()
 | |
| 
 | |
| 	cores := cluster.Cores
 | |
| 
 | |
| 	// make it easy to get access to the active
 | |
| 	core := cores[0].Core
 | |
| 	vault.TestWaitActive(t, core)
 | |
| 
 | |
| 	client := cores[0].Client
 | |
| 	client.SetToken(cluster.RootToken)
 | |
| 
 | |
| 	// Write a value that we will use with wrapping for lookup
 | |
| 	_, err := client.Logical().Write("secret/foo", map[string]interface{}{
 | |
| 		"zip": "zap",
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// Set a wrapping lookup function for reads on that path
 | |
| 	client.SetWrappingLookupFunc(func(operation, path string) string {
 | |
| 		if operation == "GET" && path == "secret/foo" {
 | |
| 			return "5m"
 | |
| 		}
 | |
| 
 | |
| 		return api.DefaultWrappingLookupFunc(operation, path)
 | |
| 	})
 | |
| 
 | |
| 	// First test: basic things that should fail, lookup edition
 | |
| 	// Root token isn't a wrapping token
 | |
| 	_, err = client.Logical().Write("sys/wrapping/lookup", nil)
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected error")
 | |
| 	}
 | |
| 	// Not supplied
 | |
| 	_, err = client.Logical().Write("sys/wrapping/lookup", map[string]interface{}{
 | |
| 		"foo": "bar",
 | |
| 	})
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected error")
 | |
| 	}
 | |
| 	// Nonexistent token isn't a wrapping token
 | |
| 	_, err = client.Logical().Write("sys/wrapping/lookup", map[string]interface{}{
 | |
| 		"token": "bar",
 | |
| 	})
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected error")
 | |
| 	}
 | |
| 
 | |
| 	// Second: basic things that should fail, unwrap edition
 | |
| 	// Root token isn't a wrapping token
 | |
| 	_, err = client.Logical().Unwrap(cluster.RootToken)
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected error")
 | |
| 	}
 | |
| 	// Root token isn't a wrapping token
 | |
| 	_, err = client.Logical().Write("sys/wrapping/unwrap", nil)
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected error")
 | |
| 	}
 | |
| 	// Not supplied
 | |
| 	_, err = client.Logical().Write("sys/wrapping/unwrap", map[string]interface{}{
 | |
| 		"foo": "bar",
 | |
| 	})
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected error")
 | |
| 	}
 | |
| 	// Nonexistent token isn't a wrapping token
 | |
| 	_, err = client.Logical().Write("sys/wrapping/unwrap", map[string]interface{}{
 | |
| 		"token": "bar",
 | |
| 	})
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected error")
 | |
| 	}
 | |
| 
 | |
| 	//
 | |
| 	// Test lookup
 | |
| 	//
 | |
| 
 | |
| 	// Create a wrapping token
 | |
| 	secret, err := client.Logical().Read("secret/foo")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if secret == nil || secret.WrapInfo == nil {
 | |
| 		t.Fatal("secret or wrap info is nil")
 | |
| 	}
 | |
| 	wrapInfo := secret.WrapInfo
 | |
| 
 | |
| 	// Test this twice to ensure no ill effect to the wrapping token as a result of the lookup
 | |
| 	for i := 0; i < 2; i++ {
 | |
| 		secret, err = client.Logical().Write("sys/wrapping/lookup", map[string]interface{}{
 | |
| 			"token": wrapInfo.Token,
 | |
| 		})
 | |
| 		if err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 		if secret == nil || secret.Data == nil {
 | |
| 			t.Fatal("secret or secret data is nil")
 | |
| 		}
 | |
| 		creationTTL, _ := secret.Data["creation_ttl"].(json.Number).Int64()
 | |
| 		if int(creationTTL) != wrapInfo.TTL {
 | |
| 			t.Fatalf("mismatched ttls: %d vs %d", creationTTL, wrapInfo.TTL)
 | |
| 		}
 | |
| 		if secret.Data["creation_time"].(string) != wrapInfo.CreationTime.Format(time.RFC3339Nano) {
 | |
| 			t.Fatalf("mismatched creation times: %q vs %q", secret.Data["creation_time"].(string), wrapInfo.CreationTime.Format(time.RFC3339Nano))
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	//
 | |
| 	// Test unwrap
 | |
| 	//
 | |
| 
 | |
| 	// Create a wrapping token
 | |
| 	secret, err = client.Logical().Read("secret/foo")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if secret == nil || secret.WrapInfo == nil {
 | |
| 		t.Fatal("secret or wrap info is nil")
 | |
| 	}
 | |
| 	wrapInfo = secret.WrapInfo
 | |
| 
 | |
| 	// Test unwrap via the client token
 | |
| 	client.SetToken(wrapInfo.Token)
 | |
| 	secret, err = client.Logical().Write("sys/wrapping/unwrap", nil)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if secret.Warnings != nil {
 | |
| 		t.Fatalf("Warnings found: %v", secret.Warnings)
 | |
| 	}
 | |
| 	if secret == nil || secret.Data == nil {
 | |
| 		t.Fatal("secret or secret data is nil")
 | |
| 	}
 | |
| 	ret1 := secret
 | |
| 	// Should be expired and fail
 | |
| 	_, err = client.Logical().Write("sys/wrapping/unwrap", nil)
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected err")
 | |
| 	}
 | |
| 
 | |
| 	// Create a wrapping token
 | |
| 	client.SetToken(cluster.RootToken)
 | |
| 	secret, err = client.Logical().Read("secret/foo")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if secret == nil || secret.WrapInfo == nil {
 | |
| 		t.Fatal("secret or wrap info is nil")
 | |
| 	}
 | |
| 	wrapInfo = secret.WrapInfo
 | |
| 
 | |
| 	// Test as a separate token
 | |
| 	secret, err = client.Logical().Write("sys/wrapping/unwrap", map[string]interface{}{
 | |
| 		"token": wrapInfo.Token,
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	ret2 := secret
 | |
| 	// Should be expired and fail
 | |
| 	_, err = client.Logical().Write("sys/wrapping/unwrap", map[string]interface{}{
 | |
| 		"token": wrapInfo.Token,
 | |
| 	})
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected err")
 | |
| 	}
 | |
| 
 | |
| 	// Create a wrapping token
 | |
| 	secret, err = client.Logical().Read("secret/foo")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if secret == nil || secret.WrapInfo == nil {
 | |
| 		t.Fatal("secret or wrap info is nil")
 | |
| 	}
 | |
| 	wrapInfo = secret.WrapInfo
 | |
| 
 | |
| 	// Read response directly
 | |
| 	client.SetToken(wrapInfo.Token)
 | |
| 	secret, err = client.Logical().Read("cubbyhole/response")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	ret3 := secret
 | |
| 	// Should be expired and fail
 | |
| 	_, err = client.Logical().Write("cubbyhole/response", nil)
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected err")
 | |
| 	}
 | |
| 
 | |
| 	// Create a wrapping token
 | |
| 	client.SetToken(cluster.RootToken)
 | |
| 	secret, err = client.Logical().Read("secret/foo")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if secret == nil || secret.WrapInfo == nil {
 | |
| 		t.Fatal("secret or wrap info is nil")
 | |
| 	}
 | |
| 	wrapInfo = secret.WrapInfo
 | |
| 
 | |
| 	// Read via Unwrap method
 | |
| 	secret, err = client.Logical().Unwrap(wrapInfo.Token)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if secret.Warnings != nil {
 | |
| 		t.Fatalf("Warnings found: %v", secret.Warnings)
 | |
| 	}
 | |
| 	ret4 := secret
 | |
| 	// Should be expired and fail
 | |
| 	_, err = client.Logical().Unwrap(wrapInfo.Token)
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected err")
 | |
| 	}
 | |
| 
 | |
| 	if !reflect.DeepEqual(ret1.Data, map[string]interface{}{
 | |
| 		"zip": "zap",
 | |
| 	}) {
 | |
| 		t.Fatalf("ret1 data did not match expected: %#v", ret1.Data)
 | |
| 	}
 | |
| 	if !reflect.DeepEqual(ret2.Data, map[string]interface{}{
 | |
| 		"zip": "zap",
 | |
| 	}) {
 | |
| 		t.Fatalf("ret2 data did not match expected: %#v", ret2.Data)
 | |
| 	}
 | |
| 	var ret3Secret api.Secret
 | |
| 	err = jsonutil.DecodeJSON([]byte(ret3.Data["response"].(string)), &ret3Secret)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if !reflect.DeepEqual(ret3Secret.Data, map[string]interface{}{
 | |
| 		"zip": "zap",
 | |
| 	}) {
 | |
| 		t.Fatalf("ret3 data did not match expected: %#v", ret3Secret.Data)
 | |
| 	}
 | |
| 	if !reflect.DeepEqual(ret4.Data, map[string]interface{}{
 | |
| 		"zip": "zap",
 | |
| 	}) {
 | |
| 		t.Fatalf("ret4 data did not match expected: %#v", ret4.Data)
 | |
| 	}
 | |
| 
 | |
| 	//
 | |
| 	// Custom wrapping
 | |
| 	//
 | |
| 
 | |
| 	client.SetToken(cluster.RootToken)
 | |
| 	data := map[string]interface{}{
 | |
| 		"zip":   "zap",
 | |
| 		"three": json.Number("2"),
 | |
| 	}
 | |
| 
 | |
| 	// Don't set a request TTL on that path, should fail
 | |
| 	client.SetWrappingLookupFunc(func(operation, path string) string {
 | |
| 		return ""
 | |
| 	})
 | |
| 	secret, err = client.Logical().Write("sys/wrapping/wrap", data)
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected error")
 | |
| 	}
 | |
| 
 | |
| 	// Re-set the lookup function
 | |
| 	client.SetWrappingLookupFunc(func(operation, path string) string {
 | |
| 		if operation == "GET" && path == "secret/foo" {
 | |
| 			return "5m"
 | |
| 		}
 | |
| 
 | |
| 		return api.DefaultWrappingLookupFunc(operation, path)
 | |
| 	})
 | |
| 	secret, err = client.Logical().Write("sys/wrapping/wrap", data)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if secret.Warnings != nil {
 | |
| 		t.Fatalf("Warnings found: %v", secret.Warnings)
 | |
| 	}
 | |
| 	secret, err = client.Logical().Unwrap(secret.WrapInfo.Token)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if secret.Warnings != nil {
 | |
| 		t.Fatalf("Warnings found: %v", secret.Warnings)
 | |
| 	}
 | |
| 	if !reflect.DeepEqual(data, secret.Data) {
 | |
| 		t.Fatalf("custom wrap did not match expected: %#v", secret.Data)
 | |
| 	}
 | |
| 
 | |
| 	//
 | |
| 	// Test rewrap
 | |
| 	//
 | |
| 
 | |
| 	// Create a wrapping token
 | |
| 	secret, err = client.Logical().Read("secret/foo")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if secret == nil || secret.WrapInfo == nil {
 | |
| 		t.Fatal("secret or wrap info is nil")
 | |
| 	}
 | |
| 	wrapInfo = secret.WrapInfo
 | |
| 
 | |
| 	// Check for correct CreationPath before rewrap
 | |
| 	if wrapInfo.CreationPath != "secret/foo" {
 | |
| 		t.Fatalf("error on wrapInfo.CreationPath: expected: secret/foo, got: %s", wrapInfo.CreationPath)
 | |
| 	}
 | |
| 
 | |
| 	// Test rewrapping
 | |
| 	secret, err = client.Logical().Write("sys/wrapping/rewrap", map[string]interface{}{
 | |
| 		"token": wrapInfo.Token,
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if secret.Warnings != nil {
 | |
| 		t.Fatalf("Warnings found: %v", secret.Warnings)
 | |
| 	}
 | |
| 
 | |
| 	// Check for correct Creation path after rewrap
 | |
| 	if wrapInfo.CreationPath != "secret/foo" {
 | |
| 		t.Fatalf("error on wrapInfo.CreationPath: expected: secret/foo, got: %s", wrapInfo.CreationPath)
 | |
| 	}
 | |
| 
 | |
| 	// Should be expired and fail
 | |
| 	_, err = client.Logical().Write("sys/wrapping/unwrap", map[string]interface{}{
 | |
| 		"token": wrapInfo.Token,
 | |
| 	})
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected err")
 | |
| 	}
 | |
| 
 | |
| 	// Attempt unwrapping the rewrapped token
 | |
| 	wrapToken := secret.WrapInfo.Token
 | |
| 	secret, err = client.Logical().Unwrap(wrapToken)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	// Should be expired and fail
 | |
| 	_, err = client.Logical().Unwrap(wrapToken)
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected err")
 | |
| 	}
 | |
| 
 | |
| 	if !reflect.DeepEqual(secret.Data, map[string]interface{}{
 | |
| 		"zip": "zap",
 | |
| 	}) {
 | |
| 		t.Fatalf("secret data did not match expected: %#v", secret.Data)
 | |
| 	}
 | |
| 
 | |
| 	// Ensure that wrapping lookup without a client token responds correctly
 | |
| 	client.ClearToken()
 | |
| 	secret, err = client.Logical().Read("sys/wrapping/lookup")
 | |
| 	if secret != nil {
 | |
| 		t.Fatalf("expected no response: %#v", secret)
 | |
| 	}
 | |
| 
 | |
| 	if err == nil {
 | |
| 		t.Fatal("expected error")
 | |
| 	}
 | |
| 
 | |
| 	var respError *api.ResponseError
 | |
| 	if errors.As(err, &respError); respError.StatusCode != 403 {
 | |
| 		t.Fatalf("expected 403 response, actual: %d", respError.StatusCode)
 | |
| 	}
 | |
| }
 |